Open yahuian opened 7 months ago
原文链接:https://time.geekbang.org/column/article/68633
一条常见的更新语句:
update user set num=num+1 where id=2;
问题背景:
如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。
解决方案:WAL
MySQL 里经常说到的 WAL 技术,WAL 的全称是 Write-Ahead Logging,它的关键点就是先写日志,再写磁盘
具体流程:
当有记录需要更新的时,InnoDB 会先把记录写到 redo log 里面,并更新内存,这个时候更新就算完成了 同时,InnoDB 会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做 InnoDB 的 redo log 是固定大小的,从头开始写,写到末尾就又回到开头循环写
write pos 是当前记录的位置,checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件
crash-safe:
有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe
redo log 是 InnoDB 引擎特有的日志,而 Server 层也有自己的日志,称为 binlog(归档日志)
不同点:
redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。 redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ” redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志 redo log 是用来 crash-safe 的,而 binlog 是用于数据恢复,备份等
两阶段提交:
数据更新 -> 写入 redo log 状态为 prepare -> 成功写入 binlog 后 -> 引擎将刚刚的 redo log 状态修改为 commit
(感觉有点像 TCP 三次握手,用来保证可靠性)
innodb_flush_log_at_trx_commit
设置成 1 的时候,表示每次事务的 redo log 都直接持久化到磁盘
sync_binlog
设置成 1 的时候,表示每次事务的 binlog 都持久化到磁盘
这样可以保证 MySQL 异常时数据不丢失
(MySQL 8.0 这两个参数默认都为 1)
原文链接:https://time.geekbang.org/column/article/68319
01 | 基础架构:一条SQL查询语句是如何执行的?
逻辑架构
MySQL 分为 Server 层和存储引擎层
连接器
负责跟客户端建立连接、获取权限、维持和管理连接
show processlist
可以查看当前连接的状态Sleep
代表当前连接出于空闲状态可能的坑
查询缓存
由于上述鸡肋问题,MySQL 8.0 删除了查询缓存功能
这块儿应该由 ORM 或者 Redis 根据业务情况来做细粒度的缓存了
分析器
SQL 语句的分析、检查
优化器
执行器
负责调用引擎的具体接口
是否有索引的区别
无索引:
有索引:
上面的无索引情况应该就是全表扫描
总结