【B+树索引】索引的使用和注意事项

一、索引的注意事项

上一篇 【B+树索引】索引页的结构含有可以快速查询的秘密 从索引页的角度认识了MySQL为了提升查询速率,使用了 B+ 树的数据结构对索引页进行了内存存储。以非叶子节点为目录项结构,叶子节点为用户记录。下面咱聊聊 InnoDB 中 B+ 树的索引的注意事项。(总结自《MySQL是怎样运行的》)

根节点是不会变的!

首先得明确一点是:聚簇索引不是咱创建的,它默认就在那的。刚开始就一个节点,那就是根节点,一个空的页。

随后有用户记录插进来了,就往这根节点的 User Records 中插入用户记录。

随着用户记录不断地增多, Free Space 部分空间逐渐减少直至为 0.

然后再插记录的话,由于根节点已经满了,此时就会发生页分裂。此时会寻一个页 a 将根节点的用户记录都复制到 页 a,再取一个页 b 存放新插入的记录。然后根节点现在即是目录项节点了,其用户记录就是主键值,映射的是页a和页b。如此往复…

此过程就是为了说明 B+ 树的根节点就是那一个,不会变,其页号不会改变

内节点中目录项记录的唯一性

就是说,二级索引也不一定会设置唯一和非空的约束的,对于二级索引记录来说,是先按二级索引列的值进行排序,在二级索引列值相同的情况下,再按照主键值进行排序。插入数据时是需要往 B+ 树中插入记录的,当二级索引出现多个相同的时,此时该如何插入呢?索引引入了主键,当二级索引相同的时候,根据主键的升序查找需要插入的位置。

一个页面至少容纳两条记录

其实这个最不难理解的,假设一个页只能容纳一条记录,那引入 B+ 树的意义又何在呢?直接查叶子节点不就好了,还费半天查目录项索引页,闲呀。

这是为什么存储可变字段,限制一个列最多存储字节的原因,然后让溢出字段存放在另一个页。这也是为什么我看很多表的创建会去使用 Dynamic 行格式的原因,如果发生溢出了直接把所有记录放到另一个页里,然后存的是那页的页号(或者说地址),我觉得就极大减少了容量,然后可以存更多的记录,当然其实 MySQL 设计者在省空间这一块算极致了。

二、回表的代价

回表的概念:就是说当使用二级索引的时候,无法从二级索引中获取查询的全部数据,得从二级索引中得到主键值然后再从聚簇索引中查找所需数据,这一个需要回到聚簇索引的过程叫做回表。

需要执行回表操作的记录越多,使用二级索引进行查询的效率也就越低,某些查询中宁愿使用全表扫描也不适用二级索引。比如:假设 key1 值在 ‘a’~‘c’ 之间的用户记录数量占所有记录的大多数,如果使用 key1 这个字段对应的二级索引,则会有大量的 id 值需要进行回表操作,这还不如直接进行全表扫描呢。

也就是说需要执行回表的操作越多,就会越倾向于使用全表扫描,反之则倾向于使用二级索引+回表的方式。而 limit 可以限制查询的记录数,这一操作可能使查询更倾向于二级索引+回表的方式。

对于需要对结果进行排序的查询,如果在采用二级索引执行查询时需要执行回表操作的记录特别多,也倾向于使用全表扫描 + 文件排序的方式进行排序。比如下面的这个查询语句:
select * from single_table order by key1
由于查询的列表是 * ,如果使用二级索引+回表的方式进行排序,则需要对所有的二级索引记录执行回表操作。这种操作的成本还不如直接遍历聚簇索引然后再进行文件排序低,所以查询优化器会倾向于使用全表扫描的方式执行查询,然后对文本进行排序。
但是如果添加了 limit 关键字,如下:
select * from single_table order by key1 limit 10
这个查询需要执行的回表操作的记录特别少,查询优化器就会倾向于使用 二级索引 + 回表的方式来执行。

三、更好的使用索引

  1. 只为用于搜索、排序或分组的列进行创建索引;
  2. 考虑索引列中不重复值的个数,即考虑回表的代价,如果某索引列的重复值太多,那会引起大量的回表操作,从而索引的效率会大大降低。
  3. 索引列的类型尽量小,让目录项节点的索引页可以存放更多的记录,也是一种预防索引树变高;
  4. 为列前缀建立索引。避免字符串太长,降低了索引的占用空间,但是注意:这种方式的排序不会走这个索引。如下面这样创建:
    alter table single_table add index idx_key1(10));
  5. 覆盖索引:即使用该二级索引我们就可以查询到自己想要的数据,而不需要进行回表,减少了索引的代价。最典型的就是通过二级索引查询主键,即不用进行回表
  6. 让索引列以列名的形式单独出现在搜索条件中,不然会导致索引失效。
  7. 主键最好是递增形式存放的,防止出现页分裂现象效率降低。

四、索引的代价

B+ 树索引在空间和时间上都有代价,所以没事儿别瞎建立索引。

空间:B+ 树索引的建立,占内存的。
时间:当执行增删操作的时候生成执行计划,而且还要给相关的二级索引进行增删,时间上也得付出代价滴。

参考:
《MySQL是怎样运行的》

题外话,一个疑问答案:为什么有了 binlog 记录操作日志,InnoDB 还要引入个 redolog 记录操作日志呢?

这还是和俩日志的作用有关系,binlog 是在 Server 层进行工作,记录的是逻辑操作,用于数据库的复制和恢复操作。而 redolog 的存在是在 InnoDB 存储引擎上工作的,它的存在是为了保障数据库的一致性和持久性。它记录的是物理操作,它在事务提交后会刷新到磁盘上。即使数据库崩溃了,redolog 也会进行数据恢复。

猜你喜欢

转载自blog.csdn.net/qq_63691275/article/details/133107237