MYSQL:聚簇索引、回表查询、索引覆盖、页分裂、日志解释

2,798 阅读5分钟

1、聚簇索引

  1. 如果表设置了主键,则主键就是聚簇索引
  2. 如果表没有主键,则会默认第一个NOT NULL,且唯一(UNIQUE)的列作为聚簇索引
  3. 以上都没有,则会默认创建一个隐藏的row_id作为聚簇索引
  4. InnoDB的聚簇索引的叶子节点存储的是行记录(其实是页结构,一个页包含多行数据)1
  • 优点
  1. 当你需要取出一定范围内的数据时,用聚簇索引也比用非聚簇索引好。
  2. 当通过聚簇索引查找目标数据时理论上比非聚簇索引要快,因为非聚簇索引定位到对应主键时还 要多一次目标记录寻址,即多一次I/O。
  3. 3.使用覆盖索引扫描的查询可以直接使用页节点中的主键值
  4. 缺点
  5. 插入速度严重依赖于插入顺序,按照主键的顺序插入是最快的方式,否则将会出现页分裂,严重 影响性能。因此,对于InnoDB表,我们一般都会定义一个自增的ID列为主键。
  6. 更新主键的代价很高,因为将会导致被更新的行移动。因此,对于InnoDB表,我们一般定义主键 为不可更新。
  7. 二级索引访问需要两次索引查找,第一次找到主键值,第二次根据主键值找到行数据。
  8. 二级索引的叶节点存储的是主键值,而不是行指针(非聚簇索引存储的是指针或者说是地址), 这是为了减少当出现行移动或数据页分裂时二级索引的维护工作,但会让二级索引占用更多的空 间。
  9. 采用聚簇索引插入新值比采用非聚簇索引插入新值的速度要慢很多,因为插入要保证主键不能重 复,判断主键不能重复,采用的方式在不同的索引下面会有很大的性能差距,聚簇索引遍历所有 的叶子节点,非聚簇索引也判断所有的叶子节点,但是聚簇索引的叶子节点除了带有主键还有记 录值,记录的大小往往比主键要大的多。这样就会导致聚簇索引在判定新记录携带的主键是否重 复时进行昂贵的I/O代价

二、回表查询

先通过普通索引的值定位聚簇索引值,再通过聚簇索引的值定位行记录数据,需要扫描两次索引B+树,它 的性能较扫一遍索引树更低

三、索引覆盖

只需要在一棵索引树上就能获取SQL所需的所有列数据,无需回表,速度更快

四、页分裂

构是 B+ 树,所谓的索引其实就是一颗 B+ 树,一个表有多少个索引就会有多少颗 B+ 树,mysql 中的数 据都是按顺序保存在 B+ 树上的(所以说索引本身是有序的)。mysql 在底层又是以数据页为单位来存储数 据的,一个数据页大小默认为 16k,当然你也可以自定义大小,也就是说如果一个数据页存满了,mysql 就会去申请一个新的数据页来存储数据,如果主键为自增 id 的话,mysql 在写满一个数据页的时候,直接 申请另一个新数据页接着写就可以了。如果主键是非自增 id,为了确保索引有序,mysql 就需要将每次插 入的数据都放到合适的位置上。当往一个快满或已满的数据页中插入数据时,新插入的数据会将数据页写 满,mysql 就需要申请新的数据页,由于可能把上个数据页中的部分数据挪到新的数据页上。这就造成了 页分裂,这个大量移动数据的过程是会严重影响插入效率的

五、日志解释MySQL中有六种日志文件,分别是:重做日志(redo log)、回滚日志(undo log)、二进制日 志(binlog)、错误日志(errorlog)、慢查询日志(slow query log)、一般查询日志(general log 中继日志(relay log)https://juejin.cn/post/6844903809118912525

redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用。

redo log是物理日志,记录的是"在某个数据页上做了什么修改";binlog是逻辑日志,记录的是这个语句的 原始逻辑,比如"给ID=2这一行的c字段加1 "。

redo log是循环写的,空间固定会用完;binlog是可以追加写入的。"追加写"是指binlog文件写到一定大小 后会切换到下一个,并不会覆盖以前的日志

数据更新操作步骤

执行器先找引擎取ID=2这一行。ID是主键,引擎直接用树搜索找到这一行。如果ID=2这一行所在的数据页 本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。

执行器拿到引擎给的行数据,把这个值加上1,比如原来是N,现在就是N+1,得到新的一行数据,再调用 引擎接口写入这行新数据。

引擎将这行新数据更新到内存中,同时将这个更新操作记录到redo log里面,此时redo log处于prepare状 态。然后告知执行器执行完成了,随时可以提交事务。

执行器生成这个操作的binlog,并把binlog写入磁盘。

执行器调用引擎的提交事务接口,引擎把刚刚写入的redo log改成提交(commit)状态,更新完成