IO流程
IO流程说明
- 首先就是用户发送一条SQL通过客户端接收之后,交由解析器解析SQL创建对应的解析树之后
- 然后优化获取对应的数据表的信息-结构
- 获取表中对应的数据表,首先就会去缓存中读取索引的如果没有就会通过IO读取在磁盘中记录索引的信息并返回
- 选择合适的索引:因为一个表会有很多的索引,MySQL会对于每一个索引进行相应的算法推敲然后再做相应的删选留下最为合适的索引,所以如果说索引的 数量多的话会给查询优化器带来一定的负担。
- 因为在当前的索引为二级索引所以这个时候就会根据二级索引的btree获取到对应的id
- 读取到所对应的id之后再通过回表查询
- 根据主键索引获取到对应的数据的页在磁盘中的位置
- 在获取数据之前会判断索引缓存的数据是否满足查询,然后再判断数据库缓冲池以及读缓冲区中是否有缓冲,如果有就返回。没有就会去执行对应的执行计 划,从磁盘中获取数据信息 Hint:可以理解为SQL中的一个优化标识,在优化器中如果对于一条语句分析完了
IO流程图例表示
IO写入流程与方式
MySQL支持用户自定义在commit时如何将log buffer中的日志刷log file中。这种控制通过变量 innodb_flush_log_at_trx_commit
的值来决定。该变量有3种值:0、1、2,默认为1。
但注意,这个变量只是控制commit
动作是否刷新log buffer
到磁盘。
innodb_flush_log_at_trx_commit 配置
innodb_flush_log_at_trx_commit = 0
innodb中的log thread每隔一秒钟将会log buffer中的数据写入文件,同时还会通知文件系统进行与文件同步的flush操作,保证数据确实已经写入磁盘。但是,每次事务的结束(commit或者rollback)并不会触发log thread将log buffer中的数据写入文件。所以当设置为0时候,在mysql crash或者oscrash或者主机断电的情况,最极端的情况是丢失一秒的数据变更。
innodb_flush_log_at_trx_commit = 1
这也是innodb默认设置
,每次事务的结束都会触发log thread将log buffer中的数据写入文件,并通知文件系统同步文件。这个设置是最安全的,能够保证不论是mysql crash,os crash还是主机断电都不会丢失任何已经提交的事务。
innodb_flush_log_at_trx_commit = 2
log thread会在每次事务结束后将数据写入事务日志,但是仅仅是调用了文件系统的写入操作,而文件系统都是有缓存的,所以log thread的写入并不能保证将文件系统中缓存写入到物理磁盘进行永久固化。文件系统什么时候将缓存中的数据同步到物理磁盘,log thread 并不知道。所以当设置为2的时候,mysql 的吵嚷声并不会造成数据的丢失,但是os crash或者主机断电可能造成事务日志的丢失,各种文件系统对文件缓存的刷新机制各不相同。
日志刷盘的规则
log buffer中未刷到磁盘的日志称为脏日志(dirty log)。
在上面的说过,默认情况下事务每次提交的时候都会刷事务日志到磁盘中,这是因为变量 innodb_flush_log_at_trx_commit 的值为1。但是innodb不仅仅只会在有commit动作后才会刷日志到磁盘,这只是innodb存储引擎刷日志的规则之一。
刷日志到磁盘有以下几种规则:
1.发出commit动作时。已经说明过,commit发出后是否刷日志由变量 innodb_flush_log_at_trx_commit 控制。
2.每秒刷一次。这个刷日志的频率由变量 innodb_flush_log_at_timeout 值决定,默认是1秒。要注意,这个刷日志频率和commit动作无关。
3.当log buffer中已经使用的内存超过一半时。
4.当有checkpoint时,checkpoint在一定程度上代表了刷到磁盘时日志所处的LSN位置。
Tips:
有一个变量 innodb_flush_log_at_timeout 的值为1秒,该变量表示的是刷日志的频率,很多人误以为是控制 innodb_flush_log_at_trx_commit 值为0和2时的1秒频率,实际上并非如此。测试时将频率设置为5和设置为1,当 innodb_flush_log_at_trx_commit 设置为0和2的时候性能基本都是不变的。
总结
设置为1时是最安全的,但由于所作的io同步操作最多,性能也是三种当中最差的;
如果设置为0,则每秒同步一次,性能相对高些,
如果设置为2,性能可能是这三种中最好的,但也有可能会出现故障后丢失的数据最多的。
至于具体应该如何设置,一般来说,如果不能完全接受数据的丢失,那可以通过牺牲一定的性能来换取数据的安全性,选择设置为1,如果允许丢失少量的数据(比如说1秒内),那么设置为0,
当然如果操作系统够稳定,主机的硬件设备足够好的话,而且主机的供电系统也足够安全的话,那么可以将innodb_flush_log_at_trx_commit=2,保证系统的高性能。