套网站模板软件,泰安seo,长春房产网官网,wordpress登录注册插件1. 更新语句在MySQL中是如何执行的#xff1f;
之前我们已经分析了MySQL架构上的整体设计原理#xff0c;现在对一条SQL语句从我们的系统层面发送到MySQL中#xff0c;然后一步一步执行这条SQL的流程#xff0c;都有了一个整体的了解。
我们已经知道了#xff0c;MVSQL最…1. 更新语句在MySQL中是如何执行的
之前我们已经分析了MySQL架构上的整体设计原理现在对一条SQL语句从我们的系统层面发送到MySQL中然后一步一步执行这条SQL的流程都有了一个整体的了解。
我们已经知道了MVSQL最常用的就是InnoDB存储引擎那么我们今天借助一条更新语句的执行来初步的了解-下InnoDB存储引擎的架构设计。
首先假设我们有一条SQL语句是这样的:
update users set namexxxwhere id10
那么我们先想一下这条SQL语句是如何执行的?
首先肯定是我们的系统通过一个数据库连接发送到了MVSQL上然后肯定会经过SQL接口、解析器、优化器、执行器几个环节解析SQL语句生成执行计划接着去由执行器负责这个计划的执行调用InnoDB存储引擎的接口去执行。
所以先看下图大致还是会走下图的这个流程 今天我们就来探索一下这个存储引擎里的架构设计以及如何基于存储引擎完成一条更新语句的执行
2. InnoDB的重要内存结构:缓冲池
InnoDB存储引擎中有一个非常重要的放在内存里的组件就是缓冲池(Buffer Pool),这里面会缓存很多的数据以便于以后在查询的时候万一你要是内存缓冲池里有数据就可以不用去查磁盘了我们看下图。 InnoDB存储引擎要执行更新语句的时候比如对“id10”这一行数据他其实会先将“id10”这一行数据看看是否在缓冲池里如果不在的话那么会直接从磁盘里加载到缓冲池里来而且接着还会对这行记录加独占锁。因为我们想一下在我们更新“id10”这一行数据的时候肯定是不允许别人同时更新的所以必须要对这行记录加独占锁
至于锁的详细分析我们后续也会有大家不用着急在这里先初步了解即可我们看下面的图 3. undo日志文件:如何让你更新的数据可以回滚?
接着下一步假设“id10”这行数据的name原来是“zhangsan”,现在我们要更新为“xxx”,那么此时我们得先把要更新的原来的值“zhangsan”和“id10”这些信息写入到undo日志文件中去。
其实稍微对数据库有一点了解的同学都应该知道如果我们执行一个更新语句要是他是在一个事务里的话那么事务提交之前我们都是可以对数据进行回滚的也就是把你更新为“xxx”的值回滚到之前的“zhangsan”去。
所以为了考虑到未来可能要回滚数据的需要这里会把你更新前的值写入undo日志文件我们看下图。 4. 更新buffer pool中的缓存数据
当我们把要更新的那行记录从磁盘文件加载到缓冲池同时对他加锁之后而且还把更新前的旧值写入undo日志文件之后我们就可以正式开始更新这行记录了更新的时候先是会更新缓冲池中的记录此时这个数据就是脏数据了。
这里所谓的更新内存缓冲池里的数据意思就是把内存里的“id10”这行数据的name字段修改为“xxx”
那么为什么说此时这行数据就是脏数据了呢?
因为这个时候磁盘上“id10”这行数据的name字段还是“zhanqsan”,但是内存里这行数据已经被修改了所以就会叫他是脏数据。
我们看下图我同时把几个步骤的序号标记出来了 5. Redo Log Buffer:万一系统宕机如何避免数据丢失?
接着我们来思考一个问题按照上图的说明现在已经把内存里的数据进行了修改但是磁盘上的数据还没修改那么此时万-MVSQL所在的机器宕机了必然会导致内存里修改过的数据丢失这可怎么办呢?
这个时候就必须要把对内存所做的修改写入到一个Redo Loq Buffer里去这也是内存里的一个缓冲区是用来存放redo日志的
所谓的redo日志就是记录下来你对数据做了什么修改比如对“id10这行记录修改了name字段的值为xxx”这就是一个日志。
我们先看下图的示意 这个redo日志其实是用来在MySQL突然宕机的时候用来恢复你更新过的数据的但是我们现在还没法直接讲解redo是如何使用的毕竟现在redo日志还仅仅停留在内存缓冲里
大家稍安勿躁继续往下看
6. 如果还没提交事务MySQL宕机了怎么办?
这里我们假设每个人看专栏的人都对MVSQL的基本SQL语法、事务的基本概念以及索引的基本概念有一个基础的了解因为但凡一个后端工程师要跟数据库打交道必然会跟这些概念有一定的了解。
所以我们都知道其实在数据库中哪怕执行一条SQL语句其实也可以是一个独立的事务只有当你提交事务之后SQL语句才算执行结束
所以这里我们都知道到目前为止其实还没有提交事务那么此时如果MVSQL崩溃必然导致内存里BufferPool中的修改过的数据都丢失同时你写入Redo Log Buffer中的redo日志也会丢失
我们看下图 那么此时数据丢失要紧吗?
其实是不要紧的因为你一条更新语句没提交事务就代表他没执行成功此时MSQL宕机虽然导致内存里的数据都丢失了但是你会发现磁盘上的数据依然还停留在原样子
也就是说“id1”的那行数据的name字段的值还是老的值“zhangsan”,所以此时你的这个事务就是执行失败了没能成功完成更新你会收到一个数据库的异常。然后当mysql重启之后你会发现你的数据并没有任何
变化。
所以此时如果mysql宕机不会有任何的问题。
7. 提交事务的时候将redo日志写入磁盘中
接着我们想要提交一个事务了此时就会根据一定的策略把redo日志从redolog buffer里刷入到磁盘文件里去
此时这个策略是通过innodb flush log at trx commit来配置的他有几个选项。
当这个参数的值为0的时候那么你提交事务的时候不会把redolog buffer里的数据刷入磁盘文件的此时可能你都提交事务了结果mysql宕机了然后此时内存里的数据全部丢失。
相当于你提交事务成功了但是由于MySQL突然宕机导致内存中的数据和redo日志都丢失了我们看下图: 当这个参数的值为1的时候你提交事务的时候就必须把redo log从内存刷入到磁盘文件里去只要事务提交成功那么redoloq就必然在磁盘里了我们看下图: 那么只要提交事务成功之后redo日志一定在磁盘文件里此时你肯定会有一条redo日志说了“我此时对哪个数据做了一个什么修改比如name字段修改为xxx了”
然后哪怕此时buffer pool中更新过的数据还没刷新到磁盘里去此时内存里的数据是已经更新过的“namexxx”,然后磁盘上的数据还是没更新过的“namezhangsan”
我们看下图提交事务之后可能处于的一个状态。 此时如果说提交事务后处于上图的状态然后mysql系统突然崩溃了此时会如何?会丢失数据吗?
肯定不会啊因为虽然内存里的修改成namexxx的数据会丢失但是redo日志里已经说了对某某数据做了修改nameXXX
所以此时mysql重启之后他可以根据redo日志去恢复之前做过的修改我们看下图。 最后来看看如果innodb_flush_log_at trx_commit参数的值是2呢?
他的意思就是提交事务的时候把redo日志写入磁盘文件对应的os cache缓存里去而不是直接进入磁盘文件可能1秒后才会把os cache里的数据写入到磁盘文件里去。
这种模式下你提交事务之后redolog可能仅仅停留在os cache内存缓存里没实际进入磁盘文件万一此时你要是机器宕机了那么os cache里的redo log就会丢失同样会让你感觉提交事务了结果数据丢了看下图。 8. 小思考题:三种redo日志刷盘策略到底选择哪一种?
今天给大家留一个小的思考题大家觉得在提交事务的时候我们对redo日志的刷盘策略应该选择哪一种?每一种刷盘策略的优缺点分别是什么?为什么?