MySQL难理解的名词解释

针对MySQL八股知识点里面难记忆、难理解的一些知识点进行重点解释。

针对MySQL八股知识点里面难记忆、难理解的一些知识点进行重点解释。

索引篇

聚簇索引

聚簇索引(Clustered Index)即索引结构和数据一起存放的索引,并不是一种单独的索引类型。InnoDB 中的主键索引就属于聚簇索引。

聚簇索引不需要回表,因为数据和索引结构放在一起,一般InnnoDB的主键索引为聚簇索引。所以优点就是查询效率快,适合排序查找和范围查找。

缺点是依赖有序的数据。

非聚簇索引

跟聚簇索引相反,就是索引结构和数据是分开存储的。二级索引,也叫辅助索引都是非聚簇索引。

MyISAM引擎的主键和非主键索引的是非聚簇索引。

优点是更新代价小,因为更新只要修改索引结构就可以了,不需要修改数据。

覆盖索引

需要查询的字段正好是索引的字段,那么直接根据该索引就能查到数据,不需要回表二次查询。

联合索引

多个字段构建的索引。

优先将区别度大的字段放到联合索引的前面。

最左前缀匹配原则

使用联合索引时,根据索引中的字段顺序,从左到右依次匹配查询条件中的字段,

例子:构建一个联合索引 (a, b, c),即查询(a),(a,b),(a,b,c)时都会走该索引。当查询条件为(a,c)时,会在(a)上触发索引。

索引下推

索引下推(Index Condition Pushdown,简称 ICP)MySQL 5.6 版本中提供的一项索引优化功能,它允许存储引擎在索引遍历过程中,执行部分 WHERE字句的判断条件,直接过滤掉不满足条件的记录,从而减少回表次数,提高查询效率。除此之外,索引下推还可以减少存储引擎层和 Server 层的数据传输量。

日志篇

事务日志redo log

Innodb存储引擎独有的,使Mysql拥有崩溃恢复的能力。

MySQL数据查询更新过程:

  1. 硬盘加载数据(页的形式)放入到缓冲池

  2. 存储引擎直接在缓冲池中更新存取数据(命中的情况下)

  3. 存储引擎在redo log buffer中记录更新信息

  4. 清空redo log buffer刷盘到redo log日志中(有不同的时机可以选择)

刷盘时机:

  1. 事务提交:事务完成提交后,log buffer的redo log会被刷新到磁盘中

  2. log buffer空间不足

  3. 事务日志缓冲区满

  4. checkpoint

  5. 后台刷新线程

事务提交redo log是否要刷新到磁盘中可以通过 innodb_flush_log_at_trx_commit 控制,有三种取值:

  • 0:表示每次提交时不进行刷盘,会出现一秒内的数据丢失。

  • 1:每次提交都进行刷盘,不会出现数据丢失。

  • 2:每次提交都只是把log buffer里的redo log写入到page cache中,而不是磁盘,写缓存的代价比写磁盘的代价低,性能相对较高。MySQL挂掉时不会出现数据丢失,宕机时可能出现一秒内的数据丢失。

为什么一秒?

InnoDB 存储引擎有一个后台线程,每隔1 秒,就会把 redo log buffer 中的内容写到文件系统缓存(page cache),然后调用 fsync 刷盘。

二进制日志bin log

无论什么存储引擎,都有bin log。逻辑日志,用于记录预计的原始逻辑,属于MySQL的server层。

MySQL 数据库的数据备份、主备、主主、主从都离不开 binlog,需要依靠 binlog 来同步数据,保证数据一致性。

写入时机:事务执行过程中,先把日志写到binlog cache中,事务提交的时候,再把binlog cache中的内容写到binlog文件中。

同时bin log也存在page cache

write:把binlog cache中的内容写到page cache。

fsync:将page cache内容刷盘。

writefsync的时机,可以由参数sync_binlog控制,默认是1

  • 0:每次提交事务都只是write,系统自行决定何时fsync

  • 1:每次提交事务都执行fsync。

  • N(N>1):累计N个事务菜fsync。

两阶段提交

redo log(重做日志)让 InnoDB 存储引擎拥有了崩溃恢复能力。

binlog(归档日志)保证了 MySQL 集群架构的数据一致性。

以基本的事务为单位,redo log 在事务执行过程中可以不断写入,而 binlog 只有在提交事务时才写入,所以 redo log 与 binlog 的写入时机不一样。

为了避免出现两个日志不一致,不知道听谁的好的情况,采取二阶段提交的策略。二阶段提交其实是redo log分二阶段提交。将redo log的写入拆成了prepare和commit两个阶段。

在执行事务时,redo log虽然处于写入状态,但是属于prepare阶段。

只有在完成事务时,binlog进行写入后,redo log才会进行commit。

回滚日志undo log

每一个事务对数据的修改都会被记录到 undo log ,当执行事务过程中出现错误或者需要执行回滚操作的话,MySQL 可以利用 undo log 将数据恢复到事务开始之前的状态。

记录的用户数据库操作的逆操作,用于崩溃恢复。

另一个作用是 MVCC ,当读取记录时,若该记录被其他事务占用或当前版本对该事务不可见,则可以通过 undo log 读取之前的版本数据,以此实现非锁定读

MVCC篇

一致性非锁定读

不需要等锁释放,读的是快照数据。在InnoDB中使用MVCC实现,在Repeatable Read下MVCC实现了可重复读和防止部分幻读。

锁定读

也叫当前读,需要加锁,读取的是最新数据,可能出现幻读。所以需要使用Next-key Lock防止当前读的幻读现象。

Read View

实际上是一个结构体,里面有一系列字段,用于存储“当前对本事务不可见的其他活跃事务”:

  • m_low_limit_id:目前出现过的最大的事务 ID+1,即下一个将被分配的事务 ID。大于等于这个 ID 的数据版本均不可见

  • m_up_limit_id:活跃事务列表 m_ids 中最小的事务 ID,如果 m_ids 为空,则 m_up_limit_idm_low_limit_id。小于这个 ID 的数据版本均可见

  • m_idsRead View 创建时其他未提交的活跃事务 ID 列表。创建 Read View时,将当前未提交事务 ID 记录下来,后续即使它们修改了记录行的值,对于当前事务也是不可见的。m_ids 不包括当前事务自己和已提交的事务(正在内存中)

  • m_creator_trx_id:创建该 Read View 的事务 ID

有一说一,这个字段命名规则确实有点恶心啊,叫low的字段的值比up大······

根据我自己的理解,m_ids 是活跃事务列表的id值,小于他的的值都是已经commit的事务,而大于他的值可能事务还没创建,m_up_limit_id是他的下界,m_low_limit_id是他的上界。每次执行select 时,会创建一个Read View ,每个Read View会有一个对应的m_creator_trx_id ,根据id值可以用来比对判断是否可见。

当用户在这个事务中要读取某个记录行的时候,InnoDB 会将该记录行的 DB_TRX_IDRead View 中的一些变量及当前事务 ID 进行比较,undo log里也存在DB_TRX_ID

在事务隔离级别 RCRR (InnoDB 存储引擎的默认事务隔离级别)下,InnoDB 存储引擎使用 MVCC(非锁定一致性读),但它们生成 Read View 的时机却不同

  • 在 RC 隔离级别下的 每次select 查询前都生成一个Read View (m_ids 列表)

  • 在 RR 隔离级别下只在事务开始后 第一次select 数据前生成一个Read View(m_ids 列表)

LICENSED UNDER CC BY-NC-SA 4.0
Comment