八股:Mysql中建索引的时候,需要注意哪些事项?(无图版本)

4 阅读8分钟

回答重点:

  1. 合理建立索引个数,索引并不是越多越好
  2. 选择合适的字段建立索引,不是所有的字段都适合建立索引

拆分讲解:

顺序:

-->使用索引有什么用?

-->既然索引这么有用,是不是越多越好?

-->既然不是越多越好,那么表中给哪些字段建立索引那?

-->扩展知识:什么是索引碎片化?

1. 使用索引有什么用那?

  • 加快查询效率:

  • 连续读取,提升效率:

  • 在聚簇索引中,数据是根据索引按照顺序排列的,有序的

  • 在进行范围查询(group by)、排序(order by)的时候

  • 定位到起始位置之后,可以按照索引顺序连续读取,不需要再回溯根节点

  • 减少了IO操作,提高了查询性能。

  • 降低树的高度,提升效率

  • 使用索引的时候(这里说的是非聚簇索引

  • 在叶子节点中存储的是索引值和主键引用

  • 相对于存储完整的数据,索引占用的空间更小

  • 节点内可以存储更的值更多

  • B+树分裂和合并的次数更少

  • 树的高度增长更慢

  • 树的高度越低,从内存中到磁盘读取的次数越少,IO操作就越少

  • 性能就越高

  • 提高缓存命中率,提升效率

  • 在从内存中读取磁盘里的数据的时候

  • 因为占用的空间少,可以存在内存的数据就更多

  • 缓存命中的概率更大,IO操作就更少,查询的效率就更快

  • 减少回表操作,提升效率:

  • 这里说的是覆盖索引

  • 当我们使用覆盖索引的时候,相比于完整的存储数据,占用的空间更少

  • 减少了IO操作(见上)

  • 如果查询的结果,在索引中均包含

  • 那么我们在通过索引获取到结果之后,便可以直接返回

  • 相当于用更少得IO到了相同的结果,提升了效率。

  • 唯一性约束:

  • 唯一索引:

  • 当我们使用唯一索引的时候,可以确保单列或者多列的组合是唯一的

  • 防止重复数据的产生

  • 简化数据管理

  • 加速连接操作:

  • 当我们进行多表连查的时候,索引的存在可以快速的定位到需要的行,避免全表扫描

  • PS:聚簇索引只存在于某些存储引擎中,如InnoDB,每张表只能有一个聚簇索引。

2. 既然索引这么好,那么是不是索引越多越好?

  • 结论:不是

  • 原因:

  • 占用空间:

  • 我们每创建一个索引,就会多创建一个B+树,所占用的空间就越大

  • 当我们建立了超级多的索引的时候,我们的存储空间便会不足,导致性能下降。

  • 不一定都能用上:

  • 虽然索引有很多好处,但是我们使用索引的时候,也有很多讲究

  • 如果使用的方法不对,我们虽然牺牲了空间,但是并没有换来性能上的提升。

  • 数据修改时,索引需要一起更改:

  • 当我们修改数据的时候,需要保证我们的索引跟着一起修改

  • 但是如果有特别多的索引,那么修改数据的耗时,可能还没有修改索引的耗时多,会影响性能。

  • 碎片化:

  • 当我们执行大量数据的修改操作后,索引可能会变的碎片化,影响查询性能。

  • 碎片化的原理和影响见扩展知识。

3. 既然索引不是越多越好,那么一张表中有那么多字段,怎么判断给哪个字段加索引,不给哪个字段加索引那?

  • 字段的选择性:(可以理解为种类,比如性别只有男、女两种)

  • 字段选择性小:

  • 不推荐建立:

  • 当一个字段的选择性很小的时候,大多数情况下不需要创建索引,因为建立了索引也不能提高查询效率。

  • 推荐举例:

  • 我们有100万数据,其中男性50万,女性50万,这时候我根据性别索引,去找名字叫凯歌的数据,怎么找?一个一个遍历。。。所以这种情况下是没有用的。

  • 推荐建立:

  • 在选择性小,但是某一方占比很大,我们需要查询占比很小的那部分数据的时候,可以建立索引。

  • 推荐建立举例:

  • 定时任务执行记录,比如我们的定时任务执行结果只有成功与失败,而基本上都是成功的时候,我们有极个别的失败,这时候我们需要找到这几个失败的记录,就可以建立索引。

  • 字段选择性大:

  • 推荐建立:

  • **减少扫描范围:**当我们一个字段有多种选择性的时候,建立索引,可以帮助我们快速的定位到数据行,减少扫描范围,避免全表扫描,提高性能,更适合建立索引。

  • 字段的增删频率:

  • 字段的增删频率频繁:

  • 不推荐建立:

  • 当我们的字段需要频繁的增删操作的时候,索引需要跟着频繁的更新,会影响性能

  • 当我们索引页进行频繁的更改的时候,需要进行频繁的合并和分裂,会导致碎片化产生,增加IO次数,影响性能。

  • 字段的增删频率不频繁:

  • 推荐建立:

  • 当我们的字段没有频繁的删除或新增操作的时候,我们的索引页不需要频繁的合并和分裂,更适合建立索引

  • 字段的大小:

  • 字段很大:

  • 不推荐建立:

  • 我们使用索引的原因主要是因为,相对于行数据来说,索引占用的空间小,单个索引页可以存储的键值对更多,从而减少了IO,提升了性能,如果一个字段很大,比如单行数据1KB,这个字段占了0.9KB,那么给这个字段建立索引在仅仅节省了一部分空间的情况下,占用了更多的空间,还不如不建立。

  • 字段比较小:

  • 推荐建立:

  • 字段小,占用的空间小,单个索引页存储的键值对多,减少了IO操作,提高了查询性能,推荐建立。

4. 扩展知识:

什么是索引碎片化?为什么会影响性能?

  • **概念:**索引在磁盘上的存储无序或者不连续,导致索引的逻辑结构和物理存储不一致。索引的物理存储,可能会存在不同的磁盘块中,形成“碎片”。

  • 原因:

  • 内部碎片化:

  • 索引存储在索引页中(也就是节点)

  • 当索引页中删除或者更新的时候,索引页内部,可能会留下未被使用的空间

  • 或者减少了索引页中存储的键值对的数量

  • 导致索引页需要分裂,于是产生碎片化。

  • 内部碎片化举例:

  • 原本一个索引页,可以存储100个键值对

  • 当我们存满后,删除了20个键值对,也就是说当前索引页还有20个键值对的空位

  • 这时候,存进来的键值对,比原来的键值对大

  • 比如原来一个键值对是1KB,现在是1.3kB

  • 那么当前索引页,所存储的键值对就少了

  • 当前索引页存储的键值对少了,那么过来20个键值对的时候,当前存不下

  • 就需要分裂,就会碎片化。

  • 外部碎片化:

  • 当我们进行大量的新增或删除的时候

  • 我们的索引页可能需要合并或者分裂

  • 这时候新的索引页,可能被分配到不同的磁盘块中

  • 导致原本连续的索引页,从物理上就不连续了

  • 我们称为外部碎片化。

  • 外部碎片化举例:

  • 假设当前索引页,存满了100个键值,索引页的最小阈值是50

  • 我们删除了51个键值对

  • 此时,索引页从相邻节点都没有借到键值对

  • 那么当前索引页就需要合并到其他索引页上(为了保持每个索引页有50%-70%的利用率,避免频繁的合并)

  • 然而合并的时候,新的索引页不在当前磁盘块上了

  • 于是就会导致索引页从物理空间上不连续

  • 也就是碎片化。

  • 扩展-为什么合并的时候新的索引页可能不再当前磁盘块:

  • 磁盘的分配机制:

  • 硬盘文件通常使用固定的块大小(4KB、16KB)来分配存储空间

  • 由于索引页里的键值被删除,导致磁盘块,需要被释放

  • 释放后,由于磁盘空间是动态分配的

  • 新的磁盘块可能没有和原本的磁盘块相连

  • 所以新分配的索引页可能不再与原来的索引页相连。