那些不走索引的SQL

"MySql中那些SQL不走索引"

Posted by Simon on August 6, 2020

“Better code, better life. ”

那些不走索引的SQL

为了提高查询效率,我们通常会在MySQL数据表建立索引。索引提高查询效率的代价是降低了插入的效率,并且并不是你建立了索引,并且你在SQL中使用到了该列,MySQL就肯定会使用到那些索引的,有一些情况很可能在你不知不觉中,你就“成功的避开了”MySQL的所有索引。

本篇文章会梳理哪些SQL不会使用索引。

现假设有quote表,instrument,market上建立了索引。

1. 索引列参与计算或者使用函数

如果where条件中age列中使用了计算或者使用了函数,则不会使用该索引

SELECT `sname` FROM `quote` WHERE `market`=20;-- 会使用索引
SELECT `sname` FROM `quote` WHERE `market`+10=30;-- 不会使用索引!!因为所有索引列参与了计算
SELECT `sname` FROM `quote` WHERE `market`=30-10;-- 会使用索引

SELECT `sname` FROM `quote` WHERE concat(``instrument``,'abc') ='Jaskeyabc'; -- 不会使用索引,因为使用了函数运算,原理与上面相同
SELECT `sname` FROM `quote` WHERE ``instrument`` =concat('Jaskey','abc'); -- 会使用索引

2. 使用like对字符串列做后缀模糊查询

SELECT * FROM `houdunwang` WHERE `uname` LIKE '前缀就走索引%' -- 走索引
SELECT * FROM `houdunwang` WHERE `uname` LIKE '后缀不走索引%' -- 不走索引

这告诉我们,如果需要查询类似email这种以.com结尾的字符串,并且希望走索引的时候,可以考虑数据库存储一个反向内容的reverse_email并设该列为索引。

3. 字符串列与数字直接比较

这是一个坑,假设有一张表,里面的a列是一个字符char类型,且a上建立了索引,你用它与数字类型做比较判断的话:

 CREATE TABLE `t1` (`a` char(10));

 SELECT * FROM `t1` WHERE `a`='1' -- 走索引
 SELECT * FROM `t2` WHERE `a`=1 -- 字符串和数字比较,不走索引!

但是如果那个表那个列是一个数字类型,拿来和字符类型的做比较,则不会影响到使用索引

 CREATE TABLE `t2` (`b` int);

 SELECT * FROM `t2` WHERE `b`='1' -- 虽然b是数字类型,和'1'比较依然走索引

但是,无论如何,这种额外的隐式类型转换都是开销,而且由于有字符和数字比就不走索引的情况,故建议避免一切隐式类型转换

尽量避免 OR 操作

select * from dept where dname='jaskey' or loc='bj' or deptno=45 --如果条件中有or,即使其中有条件带索引也不会使用。换言之,就是要求使用的所有字段,都必须建立索引

所以除非每个列都建立了索引,否则不建议使用OR,在多列OR中,可以考虑用UNION 替换:

select * from dept where dname='jaskey' union
select * from dept where loc='bj' union
select * from dept where deptno=45