本文转载自微信公众号「码上Java」,作者码上Java。转载本文请联系码上Java公众号。
前言
上一篇文章中我们一起探讨了索引的底层原理及为什么我们常用B+树作为索引的数据结构。本文我们一起学习一下索引创建的原则,看看什么时候适合创建索引?看看什么时候不适合创建索引?
什么情况下适合创建索引
1. 字段的数值有唯一性的限制,比如用户名
索引本身可以起到约束的作用,比如唯一索引、主键索引都是可以起到唯一性约束的,因此在我们的数据表中,如果某个字段是唯一性的,就可以直接创建唯一性索引,或者主键索引。
2. 频繁作为 WHERE 查询条件的字段,尤其在数据表大的情况下
在数据量大的情况下,某个字段在 SQL 查询的 WHERE 条件中经常被使用到,那么就需要给这个字段创建索引了。创建普通索引就可以大幅提升数据查询的效率。
3. 需要经常 GROUP BY 和 ORDER BY 的列
索引就是让数据按照某种顺序进行存储或检索,因此当我们使用 GROUP BY 对数据进行分组查询,或者使用 ORDER BY 对数据进行排序的时候,就需要对分组或者排序的字段进行索引。
4.UPDATE、DELETE 的 WHERE 条件列,一般也需要创建索引
对数据按照某个条件进行查询后再进行 UPDATE 或 DELETE 的操作,如果对 WHERE 字段创建了索引,就能大幅提升效率。原理是因为我们需要先根据 WHERE 条件列检索出来这条记录,然后再对它进行更新或删除。如果进行更新的时候,更新的字段是非索引字段,提升的效率会更明显,这是因为非索引字段更新不需要对索引进行维护。
不过在实际工作中,我们也需要注意平衡,如果索引太多了,在更新数据的时候,如果涉及到索引更新,就会造成负担。
5.DISTINCT 字段需要创建索引
有时候我们需要对某个字段进行去重,使用 DISTINCT,那么对这个字段创建索引,也会提升查询效率。
6. 做多表 JOIN 连接操作时,创建索引需要注意以下的原则
连接表的数量尽量不要超过 3 张,因为每增加一张表就相当于增加了一次嵌套的循环,数量级增长会非常快,严重影响查询的效率。
对 WHERE 条件创建索引,因为 WHERE 才是对数据条件的过滤。如果在数据量非常大的情况下,没有 WHERE 条件过滤是非常可怕的。
对用于连接的字段创建索引,并且该字段在多张表中的类型必须一致。
什么情况适合创建索引
1. 频繁更新的字段不适合建立索引。
这个是为什么呢?你要知道,索引为什么能够提高查询效率呢,那是因为索引在插入数据的时候会对数据进行排序。所以说,如果涉及频繁更新的字段的话,这个时候就不适合建立索引了。
这里以B+ 树索引为例(B+ 树索引是数据库中最为常见的一种索引数据结构,几乎所有的关系型数据库都支持它),B+ 树在插入时就要对数据进行排序,其实排序的开销成本并没有多大,那是因为排序是 CPU 操作(当前一个时钟周期 CPU 能处理上亿指令)。如果面对数据顺序或者逆序插入的时候还好,这个时候B+ 树索引维护成本比较低,因为叶子节点都是从左往右进行插入操作,比如自增 ID 的插入、时间的插入(若在自增 ID 上创建索引,时间列上创建索引,则 B+ 树插入通常是比较快的)。
但是如果插入的数据是无序的,B+ 树为了维护排序,需要对页进行分裂、旋转等开销较大的操作,另外,即便对于固态硬盘,随机写的性能也不如顺序写,所以磁盘性能也会收到较大影响。比如用户昵称,每个用户注册时,昵称大多都是随意取的,如果在昵称上创建索引,插入是无序的,索引维护需要的开销会比较大。
2. WHERE条件中用不到的字段不适合建立索引。
这个是为什么呢?索引的价值是快速定位,如果起不到定位的字段通常是不需要创建索引的。
3. 数据比较少的情况不适合建立索引。
这个是为什么呢?这个很简单,那是因为在数据量不大的情况下,没必要用索引,全表扫描的速度已经很快了,即使你用了索引,索引就发挥不出作用了,没卵用。
4. 唯一性太差的字段不适合建立索引。
这个是为什么呢?这个也很简单,你可以想象一种非常极端的情况,假设数据表中的数据都一样(不可能),你使用索引也一样没卵用。
我们可以以性别这个字段为例,性别无外乎两种可能,男的或者女的(这里别有杠精哈),因为你访问索引需要付出额外的IO开销,你从索引中拿到的只是地址(记住只是地址哦),要想真正访问到数据还是要对表进行一次IO。假如你要从表的100万行数据中取几个数据,那么利用索引迅速定位,访问索引的这IO开销也是非常值了。但如果你是从100万行数据中取50万行数据,就比如性别字段吧,那你相对需要访问50万次索引,再访问50万次表,加起来的开销可想而知。并不会比直接对表进行一次完整扫描小。所以即使你用了索引,没卵用。
5. 参与列计算的列不适合建索引。
这个是为什么呢?这个是因为,如果索引列上有函数运算的话,会导致不走索引,也就是索引失效了 。
举个例子,比如你在在T表上有一个索引Y,但是你的查询语句是这样子SELECT * FROM T WHERE FUN(Y) = XXX。这个时候索引也不会被用到,因为你要查询的列中所有的行都需要被计算一遍。
总结
今天我们一起索引使用相关原则进行了简单梳理,要记住:索引是能够提升SQL 查询的效率,但是索引不是万能的,一定要遵守基本原则。