知识梳理Mysql篇(三)
前言
该篇文章主要接着《知识梳理Mysql篇(二)》的题干把剩下的内容补充完整。
日志
Mysql中日志主要有以下几种BinLog、SlowLog、RelayLog、RedoLog(Innodb)、UndoLog(Innodb)。下面通过表格大致描述各个日志的作用:
日志类型 | 作用 |
---|---|
BinLog | BinLog日志是Mysql Server层实现的日志,其作用主要是实现主从复制以及备份恢复。其格式有三种STATEMENT、ROW、MIXED。 |
SlowLog | SlowLog主要是记录慢SQL,平常我们需要时需要看下slow_query_log是否开启。 |
RelayLog | RelayLog(中继日志)主要用在主从复制中,IO线程将主库的BinLog写入RelayLog之后SQL线程执行RelayLog里的语句 |
RedoLog | RedoLog主要是用在Mysql断电等故障修复 |
UndoLog | UndoLog主要用在事务回滚以及MVCC机制上 |
RedoLog
这里单独将RedoLog拎出来讲是因为这里面有些Mysql的优化机制在里面。Mysql写入磁盘的操作是随机写,为了提升Mysql的IO性能,因此Mysql先将操作顺序写入日志,待到一定的时机在刷新到磁盘(WAL)。WAL机制也让Mysql拥有了宕机恢复的能力。最近读到一篇关于Mysql日志的文章写的很不错,这里放着留个记录。
– 《MySQL 日志:undo log、redo log、binlog 有什么用?》
MVCC
多版本并发控制依靠的是ReadView机制、Undo Log、以及4个隐式的字段实现。
ReadView
在可重复读隔离级别,当事务开启,执行任何查询sql时会生成当前事务的一致性视图read-view,该视图在事务结束之前都不会变化(如果是读已提交隔离级别在每次执行查询sql时都会重新生成),这个视图由执行查询时所有未提交事务id数组(数组里最小的id为min_id)和已创建的最大事务id(max_id)组成,事务里的任何sql查询结果需要从对应版本链里的最新数据开始逐条跟read-view做比对从而得到最终的快照结果。
版本链比对规则
- 如果 row 的 trx_id 落在绿色部分( trx_id<min_id ),表示这个版本是已提交的事务生成的,这个数据是可见的;
- 如果 row 的 trx_id 落在红色部分( trx_id>max_id ),表示这个版本是由将来启动的事务生成的,是不可见的(若
row 的 trx_id 就是当前自己的事务是可见的); - 如果 row 的 trx_id 落在黄色部分(min_id <=trx_id<= max_id),那就包括两种情况
a. 若 row 的 trx_id 在视图数组中,表示这个版本是由还没提交的事务生成的,不可见(若 row 的 trx_id 就是当前自
己的事务是可见的);
b. 若 row 的 trx_id 不在视图数组中,表示这个版本是已经提交了的事务生成的,可见。
对于删除的情况可以认为是update的特殊情况,会将版本链上最新的数据复制一份,然后将trx_id修改成删除操作的
trx_id,同时在该条记录的头信息(record header)里的(deleted_flag)标记位写上true,来表示当前记录已经被
删除,在查询时按照上面的规则查到对应的记录如果delete_flag标记位为true,意味着记录已被删除,则不返回数
据。
UndoLog日志版本链
undo日志版本链是指一行数据被多个事务依次修改过后,在每个事务修改完后,Mysql会保留修改前的数据undo回滚日志,并且用两个隐藏字段trx_id和roll_pointer把这些undo日志串联起来形成一个历史记录版本链。
SQL优化
执行计划
Mysql的执行计划有助于优化我们写的SQL,之前有次面试官让我把执行计划的字段全背一遍,我是觉得只要当我们看到执行结果后明白里面字段的意思就可以了。作者一般比较关注下面几个字段type、possible_keys、key、row、extra。
字段 | 说明 |
---|---|
type | 表的连接类型,其值以及性能高低:system > eq_ref > ref > range > index > ALL |
possible_keys | 指出 MySQL 使用哪个索引在该表找到行记录。如果该值为 NULL,说明没有使用索引,可以建立索引提高性能 |
key | 显示 MySQL 实际使用的索引。如果为 NULL,则没有使用索引查询 |
row | 根据表统计信息及选用情况,大致估算出找到所需的记录或所需读取的行数,数值越小越好 |
extra | 包含不适合在其他列中显示但十分重要的额外信息。 |
extra常见值
值 | 说明 |
---|---|
using filesort | Mysql对数据使用一个外部索引进行排序 |
using temporary | Mysql使用一个临时表保存中间结果,常见于orderBy和groupBy |
using index | select操作覆盖了索引 |
using where | where子语句限制了哪一行 |
using join buffer | 使用连接缓存 |
using distinct | 发现第一个匹配后,停止为当前行组合搜索更多的行 |
using index condition | 使用了索引下推 |
最左侧原则
最左侧原则一般是用在联合索引上,针对这个其实我们只要对B+树的索引结构有大致的了解即可,下面举个例子:假设我有一个Table字段如下且有索引idx_product_id_stock
:
id | product_id | stock | store_house_id |
---|---|---|---|
1 | 1 | 2 | 1 |
2 | 2 | 600 | 1 |
8 | 2 | 500 | 2 |
9 | 3 | 500 | 3 |
那么它的B+树的结构大致是下面这样:
我们将这幅图理解其实对于索引能不能命中基本都能做出一个判断。
索引失效
like '%zhang'
、is_null
、or
、not in
、(5.7以后根据数量自动判定)in
、!=
等这些都不会走索引- 根据最左侧原则做出判断,如
>
也会导致后面的索引失效
数据倾斜
数据倾斜主要发生在Join这种连表查询中,虽然目前业务代码一般是不允许直接用Join,但这里还是提一下,当我们一定要连表查询时尽量保证我们的驱动表是小表。
应用层面分库分表
首先作者认为设计初期没必要考虑分库分表,因为这会导致代码复杂度。当我们必须去考虑数据倾斜问题以及后续扩展问题。这个还是根据自己具体的业务选择垂直拆分还是水平拆分。
新版本特性
看了一些Mysql8.0的新特性,对于平常开发上比较有帮助的是以后我们在大型表上ADD COLUMN
默认使用instant算法,执行速度会非常快。这里放一下官方原话:Therefore, ADD/DROP COLUMN operations aren't dependent on the table size anymore. In other words, the time taken to ADD/DROP new/old column(s) to/from a table with 1 row would be the same as time taken to ADD/DROP new/old column(s) to/from a table having 100M rows.
。以下是官方链接以及执行速度对比图:
好了大概就这么多东西吧~