SQL优化里面主要是围绕索引来展开的,SQL优化的一大重点就是避免索引失效,因为索引失效就会导致全表扫描,数据量很大的情况下能明显感受到查询速度的降低。
下面说说索引失效的各种场景。
- 使用索引的时候,进行了类型的隐式转换。举个例子,比如person_no是varchar类型的12345,这时候查询应该是【select * from table where person_no='12345';】,这时候索引就是有效的,但是如果误把查询写成【select * from table where person_no=12345;】,也是能查出数据,但是会进行类型转换再进行匹配,这时候就会导致索引失效。其他类型的隐式转换(如 DATE 和字符串的转换)也可能导致失效,不同字符集的隐式转换(如 utf8mb4 和 latin1)也可能失效,查询的时候确保条件值与字段类型一致。
- where条件里用到or,如果两边字段都有索引,可能会触发索引合并(Index Merge);若一边无索引,则全表扫描。这里可以考虑为or条件中的字段添加索引,或用union替代or。
- 不符合最左前缀法则,如果建立了联合索引(A,B,C),在where条件中只使用了B和C条件,就会导致这个联合索引失效,所以一定要包含A。如果包含A和C的情况下,C的索引也是失效的,因为B不在条件中,所以如果想要C也生效就得加上B的相关条件。
- 用到is not null语法。当对某个字段创建索引的时候,该字段上大多字段都是有值的才有这个需求,此时如果字段允许 NULL 且存在索引,如果用is null查询为null的数据索引可能有效,但是用is not null查询非null的记录时,如果大部分数据非 NULL,优化器可能选择全表扫描,导致索引失效。
- 用到not in语法或者!=,查询不在某一集合以外的元素,会导致全表扫描。使用 left join 或 not exists 优化 not in。
- 用到>或者<或者between and语法,范围查询对当前列索引有效,但联合索引中后续列无法使用索引。例如【select * from table where a > 100 and b = 200;
a 走索引,b 无法走索引
】,建议优化为将等值条件列放在联合索引左侧。
- 使用模糊查询like可能会导致索引失效,此时用'%xxx'匹配就必然会导致索引失效,如果用‘xxx%’这时候索引可能就还有用,简单来说就是模糊查询尽量不要匹配后缀,而是匹配前缀。如果使用全文索引(如 MySQL 的
FULLTEXT
),可优化模糊查询。
- 对在条件中对索引列进行运算操作,也会导致索引失效。例如对person_no建立了单列索引,需要查询person_no的前三位是'123'的数据,查询语句为【select id,person_no from table where substring(person_no, 1, 3)='123'】,这时候进行了substring操作,导致了索引失效,所以查询的时候避免对索引列运算。
- 数据分步过于集中,例如性别字段,只有男和女两种可能,索引也不建议建立在这样的字段上。