回答重点:
- 合理建立索引个数,索引并不是越多越好
- 选择合适的字段建立索引,不是所有的字段都适合建立索引
拆分讲解:
顺序:
-->使用索引有什么用?
-->既然索引这么有用,是不是越多越好?
-->既然不是越多越好,那么表中给哪些字段建立索引那?
-->扩展知识:什么是索引碎片化?
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)来分配存储空间
-
由于索引页里的键值被删除,导致磁盘块,需要被释放
-
释放后,由于磁盘空间是动态分配的
-
新的磁盘块可能没有和原本的磁盘块相连
-
所以新分配的索引页可能不再与原来的索引页相连。