前言

该篇文章主要接着《知识梳理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,之前有次面试官让我把执行计划的字段全背一遍,我是觉得只要当我们看到执行结果后明白里面字段的意思就可以了。作者一般比较关注下面几个字段typepossible_keyskeyrowextra

字段 说明
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_nullornot 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
好了大概就这么多东西吧~