前言

该篇文章主要接着《知识梳理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做比对从而得到最终的快照结果。

版本链比对规则
  1. 如果 row 的 trx_id 落在绿色部分( trx_id<min_id ),表示这个版本是已提交的事务生成的,这个数据是可见的;
  2. 如果 row 的 trx_id 落在红色部分( trx_id>max_id ),表示这个版本是由将来启动的事务生成的,是不可见的(若
    row 的 trx_id 就是当前自己的事务是可见的);
  3. 如果 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,意味着记录已被删除,则不返回数
    据。
    image.png
UndoLog日志版本链

undo日志版本链是指一行数据被多个事务依次修改过后,在每个事务修改完后,Mysql会保留修改前的数据undo回滚日志,并且用两个隐藏字段trx_id和roll_pointer把这些undo日志串联起来形成一个历史记录版本链。
image.png

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+树的结构大致是下面这样:
image.png
我们将这幅图理解其实对于索引能不能命中基本都能做出一个判断。

索引失效

  • 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.。以下是官方链接以及执行速度对比图:

– 《MySQL 8.0 即时添加和删除列》

image.png
好了大概就这么多东西吧~