binlog_group_commit_sync_delay=N:在等待N μs后,开始事务刷盘
binlog_group_commit_sync_no_delay_count=N:如果队列中的事务数达到N个,就忽视binlog_group_commit_sync_delay的设置,直接开始刷盘(图中Sync binlog)
-
依次将Redo log中已经prepare的事务在引擎层提交(图中InnoDB Commit)
Commit阶段不用刷盘,如上所述,Flush阶段中的Redo log刷盘已经足够保证数据库崩溃时的数据安全了
1 read view 事务开始时会对现有的活动事务进行一次快照,被称为read view,每次事务结束时才能被销毁
2 行版本号 innodb的每行都有隐藏的列,我们需要记住trx_id(活动事务号),代表最新的事务ID,指向undo历史版本的指针
具体过程
1 即MVCC一致性度是在事务启动时,获取当前活跃事务列表。
2 如果事务ID小于read view的最小事务ID,则可以直接读取
3 如果事务ID 大于等于read view的最大事务ID+1,则去undo中去寻找需要的快照版本
4 如果事务ID 介于这两者之间,则进行具体判断,如果存在与活动事务列表中,则需要读取undo的历史版本快照
不可重复性读 一个事务内读取表中的某一行数据,多次读取结果不同
解决方式:利用MVCC机制解决可重复读-针对select操作
幻读 一个事务内读取表中某个范围的数据,多次读取结果不同
说明 MySQL对于update,insert,delete使用的都是当前读模式,读取的都是当前最新的数据,所以需要添加gap锁
解决方式:利用间隙锁解决幻读问题-针对update,insert,delete
0 代表mysql每秒刷新到文件系统缓存,然后触发os 刷新到硬盘,mysqld进程或者linux的崩溃会导致上一秒钟所有事务数据的丢失。
1 代表mysql每个事务都会写入文件系统缓存刷新到硬盘, 当mysql/linux出现故障时最多损失一个事务(依赖mysql刷新函数,不依赖于系统刷新函数)
2 代表mysql每个事务都会刷新到文件系统缓存,然后os 每秒刷新缓存到硬盘 当mysql挂掉后 最多损失一个事务,只有在操作系统崩溃或者系统掉电的情况下,上一秒钟所有事务数据才可能丢失
五 半同步复制
after_commit 5.6
1 客户端提交事务
2 存储层提交事务
3 sync binlog->slave
4 收到ack-信息
5 客户端返回-commitOK
after_sync 5.7
1 客户端提交事务
2 sync binlog->slave
3 收到ack-信息(独立ack应答线程)
4 存储引擎层提交事务
5 客户端返回-commitOK
总结
1 after_commit 在于先在存储引擎提交事务再等待ack信息,假如在发送binlog的时候就发生切换,但是这时候主库已经提交了事务,主库数据丢失
2 在存储引擎层提交事务,当前事务看不到,但是其他事务是能发现的
六MySQL online_ddl
一 分类
1 copy-server-临时表(不可见文件,阻塞读写,kill后会释放空间)
2 inplace-innodb层(不阻塞读写)
1 norebuild-在原表进行操作,消耗成本低,由于不涉及表的重建,除创建添加索引,会产生部分二级索引的写入操作外,其余操作均只修改元数据项,即只在原表路径下产生.frm文件,不会申请row log,不会消耗过多的IO,速度通常很快。
2 rebuild-生成新的临时表,消耗成本高,INPLACE的rebuild table方式和COPY的rebuild table方式类似,都会扫描原表数据和构建临时文件。对于很大的表来说,这个操作是很消耗 IO 和 CPU 资源的。
二 常见操作
1 index操作-inplace-norebuild
2 column操作
1 增减普通列-inplace-rebuild
2 更改列类型-inplace-rebuild-阻塞写
3 varchar类型扩和缩
inplace-rebuild 需要5.7+扩目标<256(字节) 否则就会锁表-走COPY
4 更改列默认值-inplace-norebuild
3 自增列和主键
1 增加主键-inplace-rebuild
2 增加自增列-inplace-rebuild-阻塞写
1 using index是利用覆盖索引,using where是在server层进行过滤,和是否回表没关系,所以是否回表只需要关注using index即可
2 using temporary
1 用到结果集存放子表数据就会出现临时表
2 先使用内存临时表,如果超过tmp_table_size大小,就使用磁盘临时表
3 可以观察Created_tmp_tables状态变量值会增加
4 常见于group by,多表联查情况
3 using filesort
1 涉及到没有使用索引的排序字段一定会出现using filesort
2 参数sort_buffer_size,超过参数的限制,则会使用磁盘临时文件进行排序
3 排序的对象包括临时表和不使用临时表情况,所以(using filesort 和using tempoary并不是一起出现 )
4 针对临时表的排序 会先使用using temporary保存临时数据,然后再在临时表上使用filesort进行排序,最后输出结果。
5 MySQL filesort有两种使用模式:
模式1: sort的item保存了所需要的所有字段,排序完成后,没有必要再回表扫描。
模式2: sort的item仅包括,待排序完成后,根据rowid查询所需要的columns。
4 NLJ和BNL
NLJ 从驱动表取一条记录,然后同被驱动表进行索引过滤结果,再取下一条记录以此类推
BNL 针对索引无效(索引失效和没有索引),将驱动表的一批数据放置在join_buffer中和被驱动表进行比较
明显降低了回标的次数和IO访问-但是依然要进行优化
hash join 针对索引无效(索引失效和没有索引),取代BNL(join_buffer内的无序数组,无法一次性定位)
5 ICP特性
1 在innodb存储引擎层实现索引的二次过滤,减少server层和innodb层的交互和回标的成本
2 查询列必须属于索引列的一部分,如果不是依然要回表,我的理解是针对联合索引最左原则失效后的一种补充优化
8 change buffer
1 InnoDB在进行DML操作非聚集非唯一索引时,会先判断要操作的数据页是不是在Buffer Pool中,如果不在就会先放到Change Buffer进行操作,然后再以一定的频率将数据和辅助索引数据页进行merge。这时候通常都能将多个操作合并到一次操作,减少了IO操作,尤其是辅助索引的操作大部分都是IO操作,可以大大提高DML性能
2 什么情况下change_buffer会失效
1 如果 delete、update 是以普通二级索引做为筛选条件,不使用change buffer
2 根据普通二级索引进行数据查询不可避免读取数据页
3 对于唯一二级索引(unique key),由于索引记录具有唯一性,因此无法缓存插入操作,但可以缓存删除操作
3 一些要点
1 change buffer会定期刷新到系统表空间,会定期merge
4 适合场景
1 数据库大部分是非唯一索引;
2 业务是写多读少,或者不是写后立刻读取;