MySQL: 3 Innodb存储引擎的架构设计
Posted 鮀城小帅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL: 3 Innodb存储引擎的架构设计相关的知识,希望对你有一定的参考价值。
1.一条SQL语句在mysql中的执行过程
update users set name='xxx' where id=10
上面这条SQL语句的执行过程如下:系统通过一个数据库连接发送到了MySQL上,然后经过SQL接口、解析器、优化器、执行器几个环节,解析SQL语句,生成执行计划,,接着去由执行器负责这个计划的执行,调用InnoDB存储引擎的接口去执行。
下面将深入去了解基于存储引擎完成一条更新语句的执行。
2.InnoDB的重要内存结构:缓冲池
InnoDB存储引擎中有一个非常重要的放在内存里的组件,就是缓冲池(Buffer Pool),这里面会缓存很多的数据,以便于以后在查询的时候,如果内存缓冲池里有数据,就可以不用去查磁盘了。
在 1 中的update案例SQL语句中,InnoDB存储引擎在执行该更新语句的时候,以“id=10” 为例,它会先查询“id=10” 这一行数据是否在缓冲池里,如果不在的话,就会直接从磁盘里加载到缓冲池里。
在更新“id=10” 这行数据的时候,是不允许别人(线程)同时更新的,所以会对这行记录加独占锁。
3.undo日志文件:让更新的数据可以回滚
在上一步中,在加锁之后,会更新数据。
写undo日志文件
在案例“id=10” 这行数据进行更新的过程中,当把原来的 "zhangsan" 更新为 “lisi” 的时候。需要把要更新的原来的值 "zhangsan" 和 “id=10” 这些信息写入到 undo 日志文件中去。
undo日志文件的作用:
在数据库中,如果我们执行一个更新语句,要是它是在一个事务里的话,那么事务提交之前都是可以对数据进行回滚的。
体现在当前案例中,就是可以将 “lisi” 的值回滚到之前的 "zhangsan" 去。
4.更新buffer pool中的缓存数据
当我们把要更新的那行记录从磁盘文件加载到缓冲池,同时对它加锁之后,而且还把更新前的旧值写入undo日志文件之后,我们就可以正式开始更新这行记录了,更新的时候,先是会更新缓冲池中的记录,此时这个数据就是脏数据了。
之所以说是脏数据,从前面的例子来说,此时 "id=10" 这行数据在内存的缓冲池中被更新为 “lisi” 了,而在磁盘中依旧还是 “zhangsan” 。此时的内存与磁盘数据不一致。
5.Redo Log Buffer:系统宕机时,避免数据丢失的方案
MySQL存在的问题,万一MySQL所在的机器宕机了,必然会导致内存里修改过的数据丢失。
解决办法,把对内存所做的修改写入到一个Redo Log Buffer里去,该内存缓冲区是用来存放redo日志的。
Redo日志的作用,它会记录下来对数据做了什么修改,比如将 "id=10这行记录修改了name字段的值为xxx",这就是一个日志。
说明,这个redo日志就是用来在MySQL突然宕机的时候,用来恢复你更新过的数据的。
6.事务未提交,MySQL宕机了怎么办?
在数据库中,哪怕执行一条SQL语句,也可以算是一个独立的事务, 只有当你提交事务之后,SQL语句才算执行结束。
问题,在没有提交事务之前,此时MySQL崩溃,必然导致内存里的Buffer Pool中的修改过的数据都丢失,同时你写入Redo Log Buffer中的 redo日志也会丢失。
此时数据丢失,是不要紧的。
因为在一条更新语句,没提交事务,就代表它没执行成功,此时MySQL宕机虽然导致内存里的数据都丢失了,但是磁盘上的数据依然还停留在原样子。
参考案例说明: 缓冲池中的都是“lisi” ,此时事务未提交就宕机了。那么这个事务算是执行失败了,没能成功完成更新,你会收到一条数据库的异常。当mysql重启之后,会发现磁盘中依旧是原来的 "zhangsan" ,并没有发生任何变化。因为回滚并抛出了异常,所以此时mysql的宕机不会有任何问题。
7.提交事务的时候将redo日志写入磁盘中
提交事务之后,会根据一定的策略来把redo日志从redo Log Buffer里刷入到磁盘文件里去。
redo日志写入策略通过 innodb_flush_log_at_trx_commit来配置,有几个选项,或者说有多个策略:0、1、2三种策略。
当参数值为0时,此时提交事务的时候,不会把redo log buffer里的数据刷入磁盘文件。此时如果提交事务了,结果mysql宕机了,会导致内存里的数据全部丢失。即使mysql重启了,也无法恢复数据,这是数据不一致的问题。
当参数值为1时,在 提交事务的时候,强制把redo log 从内存刷入到磁盘文件里去,只要事务提交成功,那么redo log 就必然在磁盘里。如果在提交事务之后,mysql系统突然宕机,在重启mysql服务后,可以根据redo日志去恢复之前做过的修改,就不存在数据丢失的问题了。
当参数值为2时,提交事务的时候,把redo日志写入磁盘文件对应的 os cache缓存里去,而不是直接进入磁盘文件,可能1秒后才会把os cache里的数据写入到磁盘文件里去。
这种模式下,在提交事务后,redo log 可能仅仅停留在os cache内存缓存里,并没有持久化到磁盘文件,万一机器宕机了,那么 os cache里的 redo log就会丢失,同样会让你感觉提交事务了,结果数据丢了。
以上是关于MySQL: 3 Innodb存储引擎的架构设计的主要内容,如果未能解决你的问题,请参考以下文章