一条SQL语句是如何执行的(查询,更新)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-opHpbLAz-1673527447201)(%E4%B8%80%E6%9D%A1SQL%E8%AF%AD%E5%8F%A5%E6%98%AF%E5%A6%82%E4%BD%95%E6%89%A7%E8%A1%8C%E7%9A%84%EF%BC%88%E6%9F%A5%E8%AF%A2%EF%BC%8C%E6%9B%B4%E6%96%B0%EF%BC%89%20fb77e3876d43405f8f25fcc4a47cfafa/Untitled.png)]
大体来说,MySQL可以分为Service和存储引擎两层
InnoDB为目前的默认存储引擎
连接器
在完成经典的TCP握手后,连接器开始确认身份。确认成功后,会在权限表中查询权限
客户端如果太长时间没有动静,连接器就会自行将他断开
可以使用长连接,可以尽量减少建立链接的动作。但是会使MySQL占用内存涨得特别快
解决方法:
1.定期断开连接
2.重新初始化链接(mysql_reset_connection)此操作需MySQL5.7及以上的版本
查询缓存
之前执行过的语句及其结果可能会被以键值对的方式直接存储在内存中
如果直接命中缓存,则会直接返回结果
但是大多数情况下,查询缓存弊大于利
缓存失效是极为频繁的,大多数时间都是查询不到结果的
MySQL8.0直接删除缓存这块功能了
分析器
如果没有命中缓存,就开始真正执行语句
分析器会先做“词法分析”,分析出各个词都是干嘛的
然后是“语法分析”。是否满足语法规
优化器
经过了分析器,MySQL知道语句的目的了。但在开始之前,还是要经过优化器处理
优化器是在表里有多个索引的时候,决定用哪个索引。或者在一个语句有多个表关联的时候,决定各个表的连接顺序
执行器
开始执行的死后,先判断对这个表有没有执行查询的权限
如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。
针对更新语句,基本也会走那一套查询语句的过程
但与查询不同的是,更新流程还涉及两个重要的日志模块
即redo log(重做日志)和binlog(归档日志)
redo log重做日志(redo log是InnoDB引擎特有的日志)
WAL技术,就是先写日志,再写磁盘
具体来说,当有一条记录需要更新的时候,InnoDb引擎就会先把记录写道redo log里面,并更新内存,这个时候更新就算完成了。同时,InnoDB引擎会在适当时候,将这个操作记录更新到磁盘 里面
,这个更新往往是在系统比较空闲的时候做
InnoDB的redo log是固定大小的,可以配置容量大小
write pos是当前记录的我i之,一边写一边后移
checkpoint是当前要擦除的位置,也是推移并且循环的,擦除记录前要把记录更新到数据文件
wirte pos和checkpoint之间的是空着的部分,可以用来记录新的操作。如果write pos 追上checkpoint,表示已经满了,这个时候需要停下来擦除一部分
有了redo log ,InnoDB就可以保证及时数据库发生异常重启。之前提交的记录都不会丢失,这个能力成为crash-safe
innodb_flush_log_at_trx_commit这个参数设置成1的时候,表示每次事务的redo log都直接持久化到磁盘。这个参数我建议你设置成1,这样可以保证MySQL异常重启之后数据不丢失。
重要的日志模块:binlog
对于Server层也有自己的日志,称为binlog(归档日志)
sync_binlog这个参数设置成1的时候,表示每次事务的binlog都持久化到磁盘。这个参数我也建议你设置成1,这样可以保证MySQL异常重启之后binlog不丢失。
两种日志的区别
1.redolog是InnoDB引擎独有的,binlog是MySQL的Server层实现的,所有引擎都可以使用
2.redo log是物理日志,记录的是”在某个数据页上做了什么修改“
binlog是逻辑日志,记录的是语句的原始逻辑
3redo log是循环写的,空间固定会用完
binlog是可以追加写入的,追加写是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以 前的日志
执行器和InnoDB引擎在执行某个简单的update语句时的内部流程:
Update T set c=c+1 where ID=2
1.执行器找到ID=2这一行。ID是主键,引擎直接用树搜索找到这一行。如果ID=2这一行所在的数据页本来就在内存中,就直接返回给执行器。否则,需要先从磁盘读入内存,然后再返回
2.执行器拿到引擎给的行数据,把这个值加上1,得到一行新的数据,再调用引擎接口写入这行新数据
3引擎将这行新数据更新到内存中,同时将这个更新操作记录到redo log里面,此时redo log处于prepare状态,然后告知执行器执行完成了,随时可以提交事务
4执行器生成这个操作的binlog,并把binlog写入磁盘
5执行器调用引擎的提交事务接口,引擎把刚刚写入的redolog改成提交状态,更新完成
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pi9ZEzcL-1673527447202)(%E4%B8%80%E6%9D%A1SQL%E8%AF%AD%E5%8F%A5%E6%98%AF%E5%A6%82%E4%BD%95%E6%89%A7%E8%A1%8C%E7%9A%84%EF%BC%88%E6%9F%A5%E8%AF%A2%EF%BC%8C%E6%9B%B4%E6%96%B0%EF%BC%89%20fb77e3876d43405f8f25fcc4a47cfafa/Untitled%201.png)]
两阶段提交
为了让两份日志之间保持逻辑一致,就要使用两阶段提交