
在进行数据库查询的时候,我们都知道索引可以加快数据查询的效率。但是在实际的业务场景下,经常会遇到即使在表中增加了索引,但是同样还是会出现数据查询慢的问题。这就需要分析数据查询慢的具体原因到底是什么了。
索引失效场景
本文以表user_info 作为分析例子,在这张表上分别创建了 idx_name 以及 idx_phone 二级索引以及 idx_age_address 联合索引。
建表sql:
CREATE TABLE IF NOT EXISTS user_info (
id bigint(20) NOT NULL AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
gender int(2) NOT NULL,
age int(10) NOT NULL,
phone_number VARCHAR(20) NOT NULL,
address VARCHAR(40) NOT NULL,
PRIMARY KEY ( id ),
KEY idx_name(name),
KEY idx_phone(phone_number),
KEY idx_age_address(age,address)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
1. 字段类型不匹配导致的索引失效
问题描述: 当在查询条件中使用的字段类型与表中定义的类型不一致时,MySQL会尝试进行类型转换,这可能导致索引未被使用。
sql示例:
SELECT * FROM user_info WHERE CAST(age AS CHAR) = '25';
在这个例子中,即使age字段有索引,但由于类型转换,索引可能不会被利用。
解决办法: 确保查询条件中的数据类型与表字段类型相匹配。
2. 被索引字段使用了表达式计算
问题描述: 如果在查询条件中对索引字段进行了数学运算或其他表达式计算,索引可能无法被使用。
sql示例:
SELECT * FROM user_info WHERE age + 5 > 30;
这里,尽管age字段有索引,但因为使用了加法运算,索引可能被忽略。
解决办法: 尽量避免在索引字段上直接进行计算,可以改写查询条件以直接使用索引字段。
3. 被索引字段使用了内置函数
问题描述: 对索引字段应用内置函数,如LENGTH()、UPPER()等,会导致索引失效。
sql示例:
SELECT * FROM user_info WHERE UPPER(name) = 'JOHN';
即便name字段有索引,由于使用了UPPER()函数,索引可能不会生效。
解决办法: 如果可能,将函数应用移至数据准备阶段或直接在数据入库时规范化数据。
4. LIKE 使用了 %X 模糊匹配
问题描述: 使用LIKE时,如果通配符%位于搜索词的开始,索引通常不会被利用,因为这需要对索引进行全表扫描。
sql示例:
SELECT * FROM user_info WHERE name LIKE '%JOHN%';
解决办法: 尽量避免在LIKE的开始使用%,或使用全文索引进行模糊匹配。
5. 索引字段不是联合索引字段的最左字段
问题描述: 对于联合索引,如果查询条件中没有包含最左侧的字段,那么索引可能不会被使用。
sql示例:
SELECT * FROM user_info WHERE address = '某地址';
尽管有idx_age_address联合索引,但因查询条件没有包含age字段,索引可能无效。
解决办法: 确保查询条件以联合索引的最左字段开始。
6. OR 分割的条件,左右两边索引不均匀
问题描述: 当使用OR连接两个条件,且只有其中一个条件上的字段有索引时,MySQL可能选择全表扫描而不是使用索引。
sql示例:
SELECT * FROM user_info WHERE age = 25 OR phone_number = '1234567890';
解决办法: 尽可能避免使用OR,或者通过UNION等方式重写查询以利用索引。
7. IN、NOT IN 可能会导致索引失效
问题描述: 当IN或NOT IN的集合过大时,MySQL可能会判断全表扫描比使用索引更高效。
sql示例:
SELECT * FROM user_info WHERE age IN (值1, 值2, ..., 值N);
解决办法: 控制IN列表的长度,或者在集合较小且经常查询时,考虑将常用查询值转化为索引覆盖查询。
总之,查询慢执行时间较长,消耗资源多,当请求 QPS 增大的时候,还会影响正常查询,从而导致数据库性能下降,严重时候数据库拖垮,所以正确设计查询,应尽量避免上述情况,确保索引的有效利用。




