SQL查询:『索引失效问题』
1、IN操作符
用IN操作符写出来的SQL直观简单、易于理解。但是在where条件中使用IN操作符是低效的。例如下面这条查询语句:
SELECT *
FROM tab_a
WHERE id IN(
SELECT a_id FROM tab_b);
你认为它会怎么执行呢?先从tab_a表中遍历数据,然后拿每行数据的id字段去tab_b表中去查找,只要找到就把这行纳入查询结果。
大错特错!事实上,RDBMS会先执行第4行的子查询,把查出的数据保存到一张临时表中,再执行主查询,利用临时表中的数据去核对主查询的where条件是否成立。
这是IN操作符低效的主要原因,因为临时表是没有索引的,要核对当前数据行的id值在临时表中是否出现,必须遍历临时表。也就是说tab_b表中即使对a_id字段建了索引也是没有用的。
推荐方案是使用表连接:
SELECT tab_a.*
FROM tab_a INNER JOIN tab_b
ON tab_a.id=tab_b.id;
或者使用EXISTS操作符:
SELECT *
FROM tab_a
WHERE EXISTS
SELECT *
FROM tab_b
WHERE tab_a.id=tab_b.a_id;
注意,NOT IN和IN存在类似的问题,也是无法利用表上的索引。
2、IS NULL和IS NOT NULL
值得一提的是,数据库是不索引空值的,也就是说即便你在一个字段上建立的索引,当针对这个字段进行查询时,还是需要遍历整张表。
3、LIKE
LIKE操作符用于模糊查询,通过使用通配符可以进行非常灵活的查询,但是如果运用不当则会造成索引失效从而影响性能。
例如,LIKE ‘%abc%‘这种两头都带通配符的查询不会使用到索引,而LIKE ‘abc%‘会使用到索引来缩小查询范围,从而提高性能。
4、where条件中的函数
where条件中如果出现函数则索引会失效,例如下面的查询语句:
SELECT *
FROM tab
WHERE substring(name,1,3)=‘abc‘;
where条件中队name字段进行了取子串的函数转换,这样,即便name字段上建了索引,这个索引在查询的时候也不会被用到。
对于这种情况,即便是下面这条语句,也比上面的那条要强得多:
SELECT *
FROM tab
WHERE NAME LIKE ‘abc%‘
5、where条件中表内字段相互交杂
在where条件中,如果出现本表内的字段相互连接或比较,则字段上的索引是无法生效的,比如下面的语句:
SELECT *
FROM tab
WHERE name||gener = ‘abcF‘
name和gender上即使有索引,也不起作用。
下面的语句也是类似的情况:
SELECT *
FROM tab
WHERE age>score
age字段和score字段都是tab表的字段,相互比较,不会引用索引。