索引是数据库中用于加速数据检索的数据结构,它可以让数据库系统不必扫描全表,而是直接定位到满足条件的记录,从而大大减少查询时间和资源消耗。TiDB支持主键索引、唯一索引、普通索引和前缀索引等多种类型的索引,用户可以根据实际业务需求来创建合适的索引。
但是,并不是所有的字段都适合建立索引,也不是索引越多越好。过多或不合理的索引会增加数据维护的开销,降低数据更新和插入的速度,占用更多的存储空间,甚至导致查询优化器选择错误的执行计划。
一、哪些情况适合建立索引
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 条件过滤是非常可怕的。
最后,对用于连接的字段创建索引,并且该字段在多张表中的类型必须一致。比如 user_id 在 product_comment 表和 user 表中都为 int(11) 类型,而不能一个为 int 另一个为 varchar 类型。
二、什么时候不需要创建索引
1. WHERE 条件(包括 GROUP BY、ORDER BY)里用不到的字段不需要创建索引,索引的价值是快速定位,如果起不到定位的字段通常是不需要创建索引的。
2. 字段中如果有大量重复数据,也不用创建索引
3. 频繁更新的字段不一定要创建索引。因为更新数据的时候,也需要更新索引,如果索引太多,在更新索引的时候也会造成负担,从而影响效率。
三、什么情况下索引失效
1. 如果索引进行了表达式计算,则会失效
2. 如果对索引使用函数,也会造成失效
3. 在 WHERE 子句中,如果在 OR 前的条件列进行了索引,而在 OR 后的条件列没有进行索引,那么索引会失效。
4. 当我们使用 LIKE 进行模糊查询的时候,后面不能是 %
5. 索引列与 NULL 或者 NOT NULL 进行判断的时候也会失效。
6. 我们在使用联合索引的时候要注意最左原则
四、SQL编写原则
1. 尽量使用预编译语句或参数化语句,而不是拼接字符串来生成动态SQL语句,这样可以避免SQL注入攻击,提高SQL执行效率,减少SQL解析开销。
2. 尽量避免使用SELECT *来查询所有列,而是只查询需要的列,这样可以减少网络传输和内存占用,提高查询速度。
3. 尽量避免使用子查询,而是使用JOIN或EXISTS等关联查询方式,这样可以减少查询层次,简化查询逻辑,提高查询效率。
4. 尽量避免使用UNION ALL来合并多个子查询的结果,而是使用JOIN或EXISTS等关联查询方式,这样可以减少数据冗余,提高查询效率。
5. 尽量避免使用ORDER BY、GROUP BY、DISTINCT等排序和去重操作,或者在使用时尽量利用索引来进行排序和去重,这样可以减少排序和去重的开销,提高查询效率。
6. 尽量避免使用HAVING子句来过滤分组后的结果,而是在WHERE子句中进行过滤,这样可以减少分组后的数据量,提高查询效率。
7. 尽量避免使用LIMIT子句来分页查询数据,而是使用索引列和条件过滤来实现分页功能,这样可以减少扫描的数据量,提高查询效率。