七.Mysql

InnoDB的4大特性

  1. 插入缓冲 insert buffer
  2. 二次重写 double write
  3. 自适应哈希索引 ahi
  4. 预读 read ahead

什么是索引,好处与坏处?

是数据库管理系统中一个排序的数据结构,帮助快速查询更新表中数据

好处:

  1. 提升数据的检索,降低数据库IO成本:使用索引的意义就是通过缩小表中需要查询的记录的数目从而加快搜索效率
  2. 降低数据排序的成本,降低cpu消耗:索引之所以查询快,是因为先将数据排序好

坏处:

  1. 占用存储空间:索引其实也是一张表,记录了主键与索引字段,一般以索引文件的形式存储在磁盘上
  2. 降低更新表的速度:表的数据发生变化,对应的索引也需要一起变更。否则索引指向的物理数据可能不对,导致索引失效

使用场景:

  1. 对非常小的表,大部分情况权标扫描效率更高
  2. 对中大型表,索引非常有效
  3. 特大型表,建立和使用的代价随着增长而增长,可以考虑分区

索引的类型

  1. 普通索引:最基本的所有,没有任何约束
  2. 唯一索引:与普通索引相似,但是具有唯一性约束
  3. 主键索引(聚集索引):特殊的唯一索引,不允许为空
  4. 复合所有(覆盖索引):将多个列组合在一起创建所有,可以覆盖多个列,不需要回表

索引的创建原则

  1. 最适合索引的列是出现在where子句中的列,或者是连接子句中的列
  2. 索引的基数越大,效果越好
  3. 根据情况创建复合索引
  4. 避免创建过多的索引,索引会额外占用磁盘空间,降低写操作效率
  5. 主键尽量选择较短的数据类型,可以有效减少索引的磁盘占用提高效率
  6. 对字符串进行索引,应该定制一个前缀长度,可以节省大量的索引空间

索引的原理

mysql的索引主要用到的是一个B+树的算法,其中的B包含以下:

  1. 二叉查找树:
    左子树的节点值 < 父节点值
    右子树的节点值 > 父节点值
    若该值是持续递增,例如:1,2,3,4,5,6 则会导致右边形成了一个链表状,深度很深

  2. 平衡二叉树
    左右子树的深度差绝对值不能超过1,若超过,则会通过节点的左旋右旋进行平衡
    旋转:
    2.1 将根绝点的左(右)孩子作为新的根节点
    2.2 将新的根节点的右(左)孩子作为原根节点的左(右)孩子
    2.3 将原根节点作为新根节点的右(左)孩子

  3. B树
    系统从磁盘内读取数据到内存,是以磁盘块为基本单位读取的,而不是需要什么读取什么
    InnoDB存储引擎中有页的概念,默认是16k,因此InnoDB每次申请磁盘空间时都会申请若干个磁盘连续地址来达到16k的大小
    3.1 特性: 每一个内存块都会存储某一个范围内的书和超出这个范围外之前和之后的地址,去指向下一个内存块
    3.2 缺点:IO的次数可能不固定,也可能导致树深度过长

  4. B+树
    是在B树的基础上进行了优化,在B+树中,所有的存储数据都是放在同一层叶子节点,而非叶子节点存储的都是key值信息,这样就可以加大每个节点存储key值的数量,降低了B+树的高度。而B树叶子节点存储的还是data数据,数据大就会导致每一页存储的数据少,导致页数多,导致树深度高
    不同点:
    4.1 非叶子节点只存储key
    4.2 所有的叶子节点之间都有一个链指针
    4.3 数据记录全部放在所有的叶子节点中

B+树所有的数据查询的IO次数都是一致的,不会像B树可能不一致。更趋向于稳定

为什么主键建议自增,或者带时间性关联?

更新主键的代价很高,因为将会导致被更新的行移动

Mysql事务隔离级

  1. 读未提交:事务中的修改,即使没有提交,对其他事务也是可见的。
    导致脏读
  1. 读已提交:事务从开始到提交之前,所做的任何修改对其他事务不可见。
    会导致不可重复读
  1. 可重复读:一个事务按相同的查询条件读取以前检索过的数据,其他事务插入了满足了其查询条件的新书剧。产生幻行
    会导致幻读
  1. 串行化

注:但是在InnoDBZHONG ,可重复读导致的幻读不存在,采用了MVCC的机制(快照),或者可以手动加锁避免

Mysql的锁机制

  1. 共享锁:读锁(S锁),多个事务对于同一个数据可以共享一把锁,都能访问数据,但是只能读不能修改
加锁方式:
select * from table where id = 1 lock in share mode;
解锁方式:
commit/rollback
  1. 排它锁:写锁(X锁),排他锁不能与其他锁共存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取改行的锁,只有获取了此锁的事务才允许对数据进行读取和修改
加锁方式:
自动:delete/update/insert默认加X锁
手动:select * from table where id = 1 for update 
解锁方式:
commit/rollback

锁的粒度

表锁:系统开销小,会锁定整张表
行锁:最大程度的支持并发处理,但也带来了最大的锁开销

什么是悲观锁,乐观锁

  1. 悲观锁(共享锁、排他锁)
    在整个数据的处理过程中,将数据处于锁定状态,往往依靠数据库提供的锁机制保证数据访问的排他性。
    为了保证隔离性,需要一致性锁定读。读取数据时给加锁,其他事务无法修改;修改数据时加锁,其他事务无法读取
  2. 乐观锁
    大多数基于数据版本记录机制实现:比如一个表中增加一个version字段,读取数据时,将版本标识一并独处,之后更新时,对版本号加1.将提交数据的版本与数据库中的版本进行对比,若大于则给与更新,若小于则视为过期数据,实际上就是通过版本号,从而实现CAS原子性更新

什么是死锁

多数情况下,可以认为如果一个资源被锁定,它总会在以后某个时间被释放。而死锁发生在多个进程访问同一数据库时,每个进程拥有的锁又刚好是其他进程锁需要的,导致所有进程都无法继续下去,互相等待就导致了死锁

降低死锁的方法:

  1. 设置锁超时时间
  2. 按顺序访问对象
  3. 避免事务中的用户交互
  4. 保持事务简短在同一个批处理中
  5. 使用低隔离级别

InnoDB的行锁是怎么实现的

  1. for update完成行锁
  2. gap 锁(间隙锁):锁的是条件范围内某一段的数据 ()
  3. next-key 锁(临界锁):锁的也是某一范围内的数据 (]

注:mysql行锁锁的是索引,而不是真的是这一行数据,若你检索条件列没有索引,则会变成表锁
如果索引是唯一索引,则降级称为record lock行锁
如果是普通索引,则为next-key lock临界锁
如果没有索引,则锁全表,表锁

mysql 的优化

  1. 首先检查下服务的状态
	1. 启动的时间,若启动时间过长,可以重启,让它释放资源(最简单的做法)
	2. mysql的默认参数:
		max_connect:最大的连接条数
		innodb_buffer_pool_size:innodb缓存池的大小(重要,如果是单纯的mysql服务器,可以调至本机内存的百分80)
		join_buffer_size
		read_buffer_size等
	3. 检查mysql相关的状态值:
		连接数
		系统的锁情况
		慢查询日志
  1. 从sql语句进行优化,尽量避免全表查询
	比如where子句后对字段
		少做函数操作
		少对字段做null判断
		少用!=或<>操作符等
	sql语句的状态也可以用explan关键字去查看
	主要的查看点是Extra的额外信息
	1. using index 表示使用了覆盖索引(在存储引擎层过滤数据且不需回表)
	2. using where 表示在server层进行过滤
	3. using index Condition 索引条件下推,表示本应该在server过滤数据但是InnoDB做了优化,把它放到存储引擎中过滤
	4. using filesort 不能直接使用索引排序
	5. using temporary 使用临时表
  1. 若以上还未能解决问题,则需关注下数据库的设计
	尽量把数据库设计的更小占用磁盘空间
	1. 一些字段的存储类型,可以根据实际情况,采用更小的数据类型代替
	2. 尽可能的定义字段都是not null,或者定义默认值
	3. 若没有变长字符串类型,而是固定大小,可以采用char代替varcher
	4. 表的主键索引尽量短切尽量不做修改,因为过长会影响一页存储的值少占用磁盘空间,且修改回导致数据的重排,这都是消耗时间的操作
	5. 合理创建索引
	6. 拆分表,比如大数据的表可以安装一定的规矩进行取模分片
  1. 系统瓶颈(成本较高):提高服务器性能,CPU,内存,内存带宽

什么是MVCC?

多版本并发控制,是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单项增长的时间戳,为每一个修改的事务保存一个版本,版本与事务时间戳做关联,读操作只能读取到该事务开始前的数据库快照,这样在读操作用不用阻塞写操作,写操作不用阻塞读操作的同事,避免了脏读和不可重复读

Mysql数据库CPU飙升,怎么处理

使用show processlist命令

  1. 查看里面跑的session情况,是不是存在消耗资源大的sql,找出消耗高的sql,explain查看下执行计划,是否走索引,还是说走了索引,由于数据量太大造成。然后根据问题去做响应的调整,一般来说是加索引、修改sql、修改mysql的内存参数之后,重新跑这些sql
  2. 也有可能每个sql的消耗资源差不多,但是突然有大量的session连接进来,这种情况可以根据数据库服务器的性能来考虑是否增大连接数,或则限制连接数

InnoDB日志

  1. redolog:在页修改的时候,先写到redo log buffer里面,然后在写到redo log的文件系统缓存里面(fwrite),然后在同步到磁盘文件(fsync)
  2. undolog:是mvcc事务的重要组成部分,当对数据做了修改的时候会产生日志并记入到系统表空间中ibdata文件里面

InnoDB是如何通过日志实现事务

  1. 事务在修改页时,要先记录undolog,在记undolog之前要记undolog的redolog,然后修改数据页,在记数据页修改的redolog。redolog(里面包含undolog的修改),这一步一定要比数据页先持久化到磁盘
  2. 当事务需要回滚的时候,因为有undolog,可以把数据页回滚到前镜像的状态
  3. 崩溃恢复时,如果redolog中事务没有对应的commit记录,那么需要用undolog把该事务的修改回滚到事务开始之前,如果有commit记录,就用redo前滚到该事务完成时并提交掉

在崩溃回复时,判断事务是否需要提交的依据是:

  1. binlog无记录,redolog无记录:在redolog写之前crash,恢复操作:回滚事务
  2. binlog无记录,redolog状态prepare:在binlog写完之前的crash,恢复操作:回滚事务
  3. binlog有记录,redolog状态prepare:binlog写完提交事务之前crash,恢复操作:提交事务
  4. binlog有记录,redolog状态commit:正常完成事务,不需要恢复

binlog的几种格式?

  1. statement(默认):每一条修改数据都会记录在binlog中,操作多行数据时,更节省空间,row更占用空间,但是row更可靠
  2. row:不记录sql语句上下文相关信息,仅保存哪条记录被修改
  3. MixedLevel:以上两种混合

如何正确清理binlog?

  1. 首先查看主从库正在使用的binlog文件名称
    show master(slave) status
  2. 删除之前备份
    purge master logs before ‘2021-01-22 00:00:00’ :删除指定时间前
    purge master logs to 'mysql-bin.000001‘ : 删除指定名字
  3. 自动删除:通过设置binlog的过期时间让系统自动删除
    show variables like ’expire_logs_days‘;
    set global expire_logs_days=30;

Mysql主从复制流程

基于3个现场的交互(多线程复制则是4类):

  1. master上面的binlog dump线程,该线程负责将master的binlog event传到slave
  2. slave上面的IO线程,该线程负责接收mater传过来的binlog,并写入relay log
  3. slave上面的sql线程,该线程负责读取relay log并执行
  4. 如果是多线程复制,sql线程制作coordinator,只负责把relay log 中的binlog读出来然后交给worker线程,woker线程负责具体binlog event的执行

Mysql如何保证复制过程中数据一致性?

mysql5.7引入无损半同步复制,引入参数rpl_semi_sync_master_wait_point,该参数默认为after_sync,指的是在切成半同步之前,事务不提交,而是接收到slave的ACK确认之后才提交事务。

Mysql如何解决主从复制的延迟性

5.5 单线程复制
5.6 多库复制
5.7 多线程复制,原理:基于group commit,只要master上面的事务是group commit的,那slave上面也可以通过多个worker线程去并发执行

主从一致性校验

工具:checksum,mysqldiff,pt-table-checksum等

Mysql备份方式,备份策略

数据的备份类型:

  1. 完全备份(常用)
    完整的数据库,包含用户表,系统表,索引,视图,存储过程。一把推荐一周备份一次
  2. 增量备份
    只备份数据库一部分的另一种方法,不使用事务日志,推荐每天只做一次差异备份
  3. 事务日志备份(常用)
    推荐每小时甚至更频繁的备份
  4. 文件备份

备份工具

  1. cp
  2. mysqldump
  3. xtrabackup
  4. lvm2 快照

备份方式:

  1. 逻辑备份:使用mysql自带的mysqldump工具进行备份
  2. 物理备份:直接拷贝表结构文件
  3. 双机热备份:主从备份机制

数据库不能停机如果备份?

可以使用逻辑备份和双机热备份

备份工具的选择

以库的大小来定,一般来说100G内的库,可以考虑使用mysqldump来做,因为轻巧灵活,备份时间可以选择在业务低峰期,可以每天进行全量备份

100G以上的库,可以考虑用xtrabackup来做,备份速度快,一般选择一周一个全备,其余每天进行增量备份

备份速率:

文件大小 mysqldump xtrabackup
20G 2分钟
80G 30分钟
100G 30分钟
300G 3小时
3T 4小时

逻辑导入时间一般是备份时间的5倍以上

mysqldump和xtrabackup实现原理?

  1. mysqldump:最简单的逻辑备份方式
    备份InnoDB表时,加上-master-data=1 -single-transaction选项,在事务开始时刻,记录binlog pos点,然后利用mvcc来获取一致数据,由于是一个长事务,在写入和更新量大的数据库是,会产生非常多的undo,影响性能
    优点:简单,可针对单标备份
    缺点:备份慢回复慢
  2. xtrabackup:物理备份+逻辑备份
    备份InnoDB表时,拷贝ibd文件,并且一致监听redo log 的变化,append到自己的事务日志文件。

猜你喜欢

转载自blog.csdn.net/qq_37629227/article/details/112935696