极客时间mysql实战 读书笔记

1. 读书记录

前面我们系统了解了一个查询语句的执行流程,并介绍了执行过程中涉及的处理模块。相信你还记得, 一条查询语句的执行过程一般是经过连接器、分析器、优化器、执行器等功能模块,最后到达存储引擎。

前面我们说过,在一个表上有更新的时候,跟这个表有关的查询缓存会失效,所以这条语句就会把表 T 上所有缓存结果都清空。 这也就是我们一般不建议使用查询缓存的原因。

而粉板和账本配合的整个过程,其实就是 MySQL 里经常说到的 WAL 技术,WAL 的全称是 Write-Ahead Logging, 它的关键点就是先写日志,再写磁盘,也就是先写粉板,等不忙的时候再写账本。

具体来说,当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log(粉板)里面,并更新内存,这个时候更新就算完成了。同时,InnoDB 引擎会在适当的时候, 将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做,这就像打烊以后掌柜做的事。

与此类似,InnoDB 的 redo log 是固定大小的,比如可以配置为一组 4 个文件, 每个文件的大小是 1GB,那么这块"粉板"总共就可以记录 4GB 的操作。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示。

write pos 和 checkpoint 之间的是"粉板"上还空着的部分,可以用来记录新的操作。如果 write pos 追上 checkpoint, 表示"粉板"满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。

有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe。

redo log 是 InnoDB 引擎特有的日志,而 Server 层也有自己的日志,称为 binlog(归档日志)。

为什么会有两份日志呢? 因为最开始 MySQL 里并没有 InnoDB 引擎。MySQL 自带的引擎是 MyISAM,但是 MyISAM 没有 crash-safe 的能力, binlog 日志只能用于归档。而 InnoDB 是另一个公司以插件形式引入 MySQL 的,既然只依靠 binlog 是没有 crash-safe 能力的, 所以 InnoDB 使用另外一套日志系统------也就是 redo log 来实现 crash-safe 能力。

binlog和redolog的区别

所在的架构层不同 redo log 是物理日志,记录的是"在某个数据页上做了什么修改";binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如"给 ID=2 这一行的 c 字段加 1 "。 追加写和循环写的区别

你可能注意到了,最后三步看上去有点"绕",将 redo log 的写入拆成了两个步骤:prepare 和 commit,这就是"两阶段提交"。

为什么必须有"两阶段提交"呢? 这是为了让两份日志之间的逻辑一致。要说明这个问题,我们得从文章开头的那个问题说起:怎样让数据库恢复到半个月内任意一秒的状态?

一条sql语句更新的过程:update T set c=c+1 where ID=2;

执行器先找引擎取 ID=2 这一行。ID 是主键,引擎直接用树搜索找到这一行。如果 ID=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。 执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数据,再调用引擎接口写入这行新数据。 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务。 执行器生成这个操作的 binlog,并把 binlog 写入磁盘。 执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新完成。

事务就是要保证一组数据库操作,要么全部成功,要么全部失败。在 MySQL 中,事务支持是在引擎层实现的

读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。 读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。 可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。 串行化,顾名思义是对于同一行记录,"写"会加"写锁","读"会加"读锁"。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

1.2 索引描述

索引的出现其实就是为了提高数据查询的效率,就像书的目录一样
索引的常见模型:哈希表、有序数组和搜索树。
哈希索引做区间查询的速度是很慢的。哈希表这种结构适用于只有等值查询的场景
有序数组用二分法就可以快速得到,这个时间复杂度是 O(log(N))。 如果仅仅看查询效率,有序数组就是最好的数据结构了。但是,在需要更新数据的时候就麻烦了,你往中间插入一个记录就必须得挪动后面所有的记录,成本太高。 有序数组索引只适用于静态存储引擎,比如你要保存的是 2017 年某个城市的所有人口信息,这类不会再修改的数据。
搜索树,这个时间复杂度是 O(log(N)), 树可以有二叉,也可以有多叉。多叉树就是每个节点有多个儿子,儿子之间的大小保证从左到右递增。二叉树是搜索效率最高的, 但是实际上大多数的数据库存储却并不使用二叉树。其原因是,索引不止存在内存中,还要写到磁盘上。 以 InnoDB 的一个整数字段索引为例,这个 N 差不多是 1200。这棵树高是 4 的时候,就可以存 1200 的 3 次方个值,这已经 17 亿了。 考虑到树根的数据块总是在内存中的,一个 10 亿行的表上一个整数字段的索引 ,查找一个值最多只需要访问 3 次磁盘。其实,树的第二层也有很大概率在内存中,那么访问磁盘的平均次数就更少了。
在 MySQL 中,索引是在存储引擎层实现的,所以并没有统一的索引标准,即不同存储引擎的索引的工作方式并不一样。而即使多个存储引擎支持同一种类型的索引, 其底层的实现也可能不同。由于 InnoDB 存储引擎在 MySQL 数据库中使用最为广泛,所以下面我就以 InnoDB 为例,和你分析一下其中的索引模型。
根据叶子节点的内容,索引类型分为主键索引和非主键索引
主键索引的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index)。 非主键索引的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)

相关推荐
技术liul2 分钟前
解决Spring Boot Configuration Annotation Processor not configured
java·spring boot·后端
HelloDam10 分钟前
基于元素小组的归并排序算法
后端·算法·排序算法
Net分享11 分钟前
在 ASP.NET Core 中使用 Confluent.Kafka 实现 Kafka 生产者和消费者
后端
HelloDam11 分钟前
单元格法近似求解多边形最大内接矩形问题【思路讲解+java实现】
后端
Winwoo13 分钟前
服务端推送 SSE
后端
Apifox1 小时前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
uhakadotcom1 小时前
使用 Model Context Protocol (MCP) 构建 GitHub PR 审查服务器
后端·面试·github
Asthenia04121 小时前
详细分析:ConcurrentLinkedQueue
后端
uhakadotcom1 小时前
Ruff:Python 代码分析工具的新选择
后端·面试·github
uhakadotcom2 小时前
Mypy入门:Python静态类型检查工具
后端·面试·github