wordpress不同分类文章不同模板,手机优化大师怎么退款,修改wordpress标签大小,成都装修设计公司推荐一条SQL【更新】语句是如何执行的 首先#xff0c;可以确定的说#xff0c;【查询】语句的那一套流程#xff0c;【更新】语句也是同样会走一遍#xff0c;与查询流程不一样的是#xff0c; 更新语句涉及到【事务】#xff0c;就必须保证事务的四大特性#xff1a;ACID可以确定的说【查询】语句的那一套流程【更新】语句也是同样会走一遍与查询流程不一样的是 更新语句涉及到【事务】就必须保证事务的四大特性ACID 所以更新流程涉及到两个重要的日志模板
redo log重做日志binlog归档日志
1 redo log
首先redo log日志是innodb引擎特有这也是innodb引擎成为mysql最主流引擎的主要原因。 《孔乙己》这篇文章酒店掌柜有一个粉板专门用来记录客人的赊账记录。如果赊账的人不多那么他可以把顾客名和账目写在板上。但如果赊账的人多了粉板总会有记不下的时候这个时候掌柜一定还有一个专门记录赊账的账本。 如果有人要赊账或者还账的话掌柜一般有两种做法 一种做法是直接把账本翻出来把这次赊的账加上去或者扣除掉 另一种做法是先在粉板上记下这次的账等打烊以后再把账本翻出来核算。 在生意红火柜台很忙时掌柜一定会选择后者因为前者操作实在是太麻烦了。首先你得找到这个人的赊账总额那条记录。你想想密密麻麻几十页掌柜要找到那个名字可能还得带上老花镜慢慢找找到之后再拿出算盘计算最后再将结果写回到账本上。这整个过程想想都麻烦。相比之下还是先在粉板上记一下方便。你想想如果掌柜没有粉板的帮助每次记账都得翻账本效率是不是低得让人难以忍受 同样在 MySQL 里也有这个问题如果每一次的更新操作都需要写进磁盘然后磁盘也要找到对应的那条记录然后再更新整个过程 IO 成本、查找成本都很高。
为了解决这个问题MySQL 的设计者就用了类似酒店掌柜粉板的思路来提升更新效率。
先写日志再写磁盘
而粉板和账本配合的整个过程其实就是 MySQL 里经常说到的 WAL 技术WAL 的全称是 Write-Ahead Logging它的关键点就是先写日志再写磁盘也就是先写粉板等不忙的时候再写账本。
具体来说当有一条记录需要更新的时候InnoDB 引擎就会先把记录写到 redo log粉板里面并更新内存这个时候更新就算完成了。
同时InnoDB 引擎会在适当的时候将这个操作记录更新到磁盘里面而这个更新往往是在系统比较空闲的时候做这就像打烊以后掌柜做的事。 如果今天赊账的不多掌柜可以等打烊后再整理。
但如果某天赊账的特别多粉板写满了又怎么办呢 这个时候掌柜只好放下手中的活儿把粉板中的一部分赊账记录更新到账本中然后把这些记录从粉板上擦掉为记新账腾出空间。
与此类似InnoDB 的 redo log 是固定大小的比如可以配置为一组 4 个文件每个文件的大小是 1GB那么这块“粉板”总共就可以记录 4GB 的操作。 从头开始写写到末尾就又回到开头循环写如下面这个图所示。 write pos 是当前记录的位置一边写一边后移写到第 3 号文件末尾后就回到 0 号文件开头。
checkpoint 是当前要擦除的位置也是往后推移并且循环的擦除记录前要把记录更新到数据文件。
write pos 和 checkpoint 之间的是“粉板”上还空着的部分可以用来记录新的操作。 如果 write pos 追上 checkpoint表示“粉板”满了这时候不能再执行新的更新得停下来先擦掉一些记录把 checkpoint 推进一下。
有了 redo logInnoDB 就可以保证即使数据库发生异常重启之前提交的记录都不会丢失这个能力称为 crash-safe。
2 binlog
redo log 是 InnoDB 引擎特有的日志而 Server 层也有自己的日志称为 binlog归档日志。
你肯定会问为什么会有两份日志呢
因为最开始 MySQL 里并没有 InnoDB 引擎。 MySQL 自带的引擎是 MyISAM但是 MyISAM 没有 crash-safe 的能力binlog 日志只能用于归档。 而 InnoDB 是另一个公司以插件形式引入 MySQL 的既然只依靠 binlog 是没有 crash-safe 能力的所以 InnoDB 使用另外一套日志系统也就是 redo log 来实现 crash-safe 能力。
这两种日志有以下三点不同。 1 redo log 是 InnoDB 引擎特有的 binlog 是 MySQL 的 Server 层实现的所有引擎都可以使用。 2 redo log 是物理日志记录的是“在某个数据页上做了什么修改” binlog 是逻辑日志记录的是这个语句的原始逻辑比如“给 ID2 这一行的 c 字段加 1 ”。 3 redo log 是循环写的空间固定会用完 binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个并不会覆盖以前的日志。
执行流程
接下来我们看一条更新sql的整体执行流程
mysql update T set cc1 where ID2;执行器先找引擎取 ID2 这一行。 ID 是主键引擎直接用树搜索找到这一行。
如果 ID2 这一行所在的数据页本来就在内存中就直接返回给执行器 否则需要先从磁盘读入内存然后再返回。
执行器拿到引擎给的行数据把这个值加上 1比如原来是 N现在就是 N1得到新的一行数据 再调用引擎接口写入这行新数据。 [server–innodb]
redo log 记录更新操作 – prepare
引擎将这行新数据更新到内存中同时将这个更新操作记录到 redo log 里面此时 redo log 处于 prepare 状态。
然后告知执行器执行完成了随时可以提交事务。 [innodb–server][记录下的是修改数据页的操作–正在处理中prepare]
binlog将更新操作写入磁盘
执行器生成这个操作的 binlog并把 binlog 写入磁盘。 [server–innodb][记录的是update T … 到binlog磁盘]
redo log 记录更新操作 – commit
执行器调用引擎的提交事务接口引擎把刚刚写入的 redo log 改成提交commit状态更新完成。 [innodb][记录下的是修改数据页的操作–处理已完成,commit]
这个 update 语句的执行流程图如下
两阶段提交
通过上面可以发现将 redo log 的写入拆成了两个步骤prepare 和 commit这就是两阶段提交”。
为什么日志需要“两阶段提交” 这里不妨用反证法来进行解释。由于 redo log 和 binlog 是两个独立的逻辑如果不用两阶段提交要么就是
先写完 redo log 再写 binlog或者采用反过来的顺序先写binlog 再写 redo log
我们看看这两种方式会有什么问题。
先写 redo log 后写 binlog。
假设在 redo log 写完binlog 还没有写完的时候MySQL 进程异常重启。 由于我们前面说过的redo log 写完之后系统即使崩溃仍然能够把数据恢复回来所以恢复后这一行 c 的值是 1。 但是由于 binlog 没写完就 crash 了这时候 binlog 里面就没有记录这个语句(update …)。 因此之后备份日志的时候存起来的 binlog 里面就没有这条语句。
然后你会发现如果需要用这个 binlog 来恢复临时库的话由于这个语句的 binlog 丢失这个临时库就会少了这一次更新恢复出来的这一行 c 的值就是 0与原库的值不同(在没有crash之前是记录的1重启后binlog没有这条sql所以为0。
先写 binlog 后写 redo log。
如果在 binlog 写完之后 crash由于 redo log 还没写崩溃恢复以后这个事务无效所以这一行 c 的值是 0。 但是 binlog 里面已经记录了“把 c 从 0 改成 1”这个日志。 所以在之后用 binlog 来恢复的时候就多了一个事务出来恢复出来的这一行 c 的值就是 1与原库的值不同(数据库原先是0系统重启后读取binlog恢复的数据多了一条设置为1。
两阶段提交是分布式事务一致性的一种解决方案。
redo log 用于保证 crash-safe 能力。
innodb_flush_log_at_trx_commit 这个参数设置成 1 的时候表示每次事务的 redo log 都直接持久化到磁盘。这样可以保证 MySQL 异常重启之后数据不丢失。
sync_binlog 这个参数设置成 1 的时候表示每次事务的 binlog 都持久化到磁盘。这样可以保证 MySQL 异常重启之后 binlog 不丢失。
innodb_flush_log_at_trx_commit redo log 持久化sync_binlog binlog 持久化