SQL中索引失效的15种高频场景及对应优化写法有哪些

来源:草根站长作者:北京GEO公司头衔:草根站长
导读:本期聚焦于小伙伴创作的《SQL中索引失效的15种高频场景及对应优化写法有哪些》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《SQL中索引失效的15种高频场景及对应优化写法有哪些》有用,将其分享出去将是对创作者最好的鼓励。

在数据库查询优化工作中,索引的正确使用是提升查询效率的关键,但很多开发者写的SQL语句看似合理,实际执行时却没有命中索引,导致查询耗时大幅增加。了解索引失效的常见场景并掌握对应的优化方法,是每一个后端开发者和数据库运维人员必备的技能。

SQL中索引失效的15种高频场景及对应优化写法有哪些

索引失效的15种高频场景及优化写法

1. 对索引字段使用函数操作

当查询条件中对索引字段使用函数时,数据库无法利用索引的有序性进行快速查找,会导致索引失效。

失效SQL示例:

-- 对create_time索引字段使用DATE函数
SELECT * FROM user WHERE DATE(create_time) = '2024-05-01';

优化写法:将函数操作转移到条件值的处理上,避免对索引字段直接操作。

-- 改为范围查询,命中create_time索引
SELECT * FROM user 
WHERE create_time >= '2024-05-01 00:00:00' 
AND create_time < '2024-05-02 00:00:00';

2. 隐式类型转换

如果查询条件中索引字段的类型和传入值的类型不匹配,数据库会进行隐式类型转换,导致索引失效。

失效SQL示例:假设user表的phone字段是varchar类型且建有索引,传入数值类型的值:

-- phone是varchar类型,传入数值会触发隐式转换
SELECT * FROM user WHERE phone = 13800138000;

优化写法:保证传入值的类型和索引字段类型一致。

-- 传入字符串类型的值,匹配phone字段类型
SELECT * FROM user WHERE phone = '13800138000';

3. like左模糊匹配

使用like进行左模糊匹配或者全模糊匹配时,索引无法发挥作用,只有右模糊匹配可以命中索引。

失效SQL示例:

-- 左模糊匹配,索引失效
SELECT * FROM article WHERE title LIKE '%SQL优化';
-- 全模糊匹配,索引失效
SELECT * FROM article WHERE title LIKE '%SQL%';

优化写法:尽量使用右模糊匹配,如果必须使用左模糊或全模糊,可考虑使用全文索引替代。

-- 右模糊匹配,命中title索引
SELECT * FROM article WHERE title LIKE 'SQL优化%';

4. 使用or连接条件且部分字段无索引

当查询条件用or连接,且or两边的字段至少有一个没有建立索引时,整个查询的索引都会失效。

失效SQL示例:假设user表只有id字段有索引,name字段无索引:

-- or连接的条件中name无索引,导致id索引也失效
SELECT * FROM user WHERE id = 1 OR name = '张三';

优化写法:给or连接的所有字段都建立索引,或者将查询拆分为两个单独的查询用union连接。

-- 拆分后用union连接,两个查询分别命中各自索引
SELECT * FROM user WHERE id = 1
UNION
SELECT * FROM user WHERE name = '张三';

5. 联合索引不满足最左前缀原则

联合索引是按照索引字段的创建顺序排序的,查询时必须从最左端的字段开始匹配,否则索引失效。

失效SQL示例:假设建立了联合索引idx_user_age_name(age, name):

-- 跳过最左字段age,直接查询name,联合索引失效
SELECT * FROM user WHERE name = '李四';

优化写法:查询条件包含联合索引最左端的字段,符合最左前缀原则。

-- 包含最左字段age,命中联合索引
SELECT * FROM user WHERE age = 20 AND name = '李四';

6. 索引字段参与运算

查询条件中对索引字段进行算术运算时,索引会失效。

失效SQL示例:

-- 对price索引字段做加法运算
SELECT * FROM goods WHERE price + 10 = 100;

优化写法:将运算转移到条件值上,避免对索引字段直接运算。

-- 调整运算逻辑,命中price索引
SELECT * FROM goods WHERE price = 90;

7. 使用不等于(!=、<>)判断

当查询条件使用不等于判断时,数据库通常会认为需要扫描大部分数据,从而放弃使用索引。

失效SQL示例:

-- 使用不等于判断,索引失效
SELECT * FROM user WHERE age != 20;
SELECT * FROM user WHERE age <> 20;

优化写法:如果业务允许,改为范围查询,或者结合其他索引字段缩小扫描范围。

-- 改为范围查询,可能命中age索引
SELECT * FROM user WHERE age < 20 OR age > 20;

8. 使用is null或者is not null判断

对于普通索引,当查询条件使用is null或者is not null时,可能触发索引失效,具体和数据库版本及数据分布有关。

失效SQL示例:

-- 使用is null判断,可能索引失效
SELECT * FROM user WHERE email IS NULL;
-- 使用is not null判断,可能索引失效
SELECT * FROM user WHERE email IS NOT NULL;

优化写法:如果字段允许,设置默认值替代null值,用等于判断替代is null判断。

-- 假设email默认值为空字符串,替代null判断
SELECT * FROM user WHERE email = '';

9. 范围查询后的联合索引字段失效

联合索引中,如果某个字段使用了范围查询,那么该字段之后的索引字段无法命中索引。

失效SQL示例:假设联合索引idx_user_age_name(age, name),age使用范围查询:

-- age是范围查询,name字段无法命中联合索引
SELECT * FROM user WHERE age > 20 AND name = '王五';

优化写法:调整联合索引的创建顺序,将范围查询的字段放在联合索引的最后一位。

-- 调整联合索引为idx_user_name_age(name, age)
-- 此时age范围查询可以命中索引
SELECT * FROM user WHERE name = '王五' AND age > 20;

10. 查询条件中使用not in

使用not in进行条件过滤时,数据库通常会放弃使用索引,进行全表扫描。

失效SQL示例:

-- 使用not in,索引失效
SELECT * FROM user WHERE age NOT IN (20, 21, 22);

优化写法:如果数据量不大,可改为not exists,或者拆分为多个小于、大于的条件。

-- 改为not exists写法,可能命中索引
SELECT * FROM user u1 WHERE NOT EXISTS (
    SELECT 1 FROM (SELECT 20 AS age UNION SELECT 21 UNION SELECT 22) t 
    WHERE t.age = u1.age
);

11. 查询条件中使用in但参数过多

虽然in通常可以命中索引,但如果in中的参数数量过多,数据库优化器可能会认为全表扫描效率更高,从而放弃索引。

失效SQL示例:in中包含上千个参数:

-- in参数过多,可能索引失效
SELECT * FROM user WHERE id IN (1,2,3,...1000);

优化写法:将参数分批查询,或者将参数存入临时表,用join的方式查询。

-- 创建临时表存储参数
CREATE TEMPORARY TABLE temp_ids (id INT PRIMARY KEY);
INSERT INTO temp_ids VALUES (1),(2),(3),...;
-- 用join查询,命中id索引
SELECT u.* FROM user u JOIN temp_ids t ON u.id = t.id;

12. 字符集不一致导致隐式转换

如果关联查询的表字符集不一致,或者查询条件中字段和值的字符集不一致,会触发隐式转换导致索引失效。

失效SQL示例:假设user表字符集是utf8mb4,order表字符集是utf8,关联查询时:

-- 字符集不一致,关联字段的索引失效
SELECT u.*, o.order_no FROM user u 
JOIN order o ON u.id = o.user_id;

优化写法:统一相关表的字符集,或者在查询时显式转换字符集(优先统一表字符集)。

-- 统一字符集后查询,关联字段正常命中索引
-- 或者临时转换字符集:
SELECT u.*, o.order_no FROM user u 
JOIN order o ON u.id = CONVERT(o.user_id USING utf8mb4);

13. 优化器认为全表扫描更快

当查询需要返回表中大部分数据时,数据库优化器会认为全表扫描的成本比走索引更低,从而放弃索引。

失效SQL示例:表中90%的数据都满足查询条件:

-- 返回大部分数据,优化器放弃索引
SELECT * FROM user WHERE age > 10;

优化写法:如果业务不需要返回所有字段,只查询带索引的字段,或者增加更精确的过滤条件缩小返回范围。

-- 只查询索引包含的字段,可能触发索引覆盖
SELECT id, age FROM user WHERE age > 10;

14. 使用select * 且无法覆盖索引

如果查询使用select *,且索引无法覆盖所有查询字段,数据库需要回表查询,当回表成本过高时可能放弃索引。

失效SQL示例:假设idx_user_age只有age字段,查询所有字段:

-- 需要回表查询所有字段,可能放弃索引
SELECT * FROM user WHERE age = 20;

优化写法:只查询需要的字段,或者建立包含所有查询字段的联合索引实现索引覆盖。

-- 只查询需要的字段,减少回表成本
SELECT id, age, name FROM user WHERE age = 20;

15. 查询条件中对索引字段使用case when

在查询条件中使用case when处理索引字段时,索引会失效。

失效SQL示例:

-- 对status字段使用case when,索引失效
SELECT * FROM order WHERE CASE WHEN status = 1 THEN 1 ELSE 0 END = 1;

优化写法:将case when的逻辑转移到查询逻辑中,避免对索引字段做复杂处理。

-- 直接写过滤条件,命中status索引
SELECT * FROM order WHERE status = 1;

索引失效排查方法

当发现SQL查询性能不符合预期时,可以通过以下方式排查是否出现索引失效:

  • 使用EXPLAIN命令查看SQL的执行计划,观察key字段是否显示了预期的索引名称,如果为null则说明没有命中索引。
  • 观察执行计划中的type字段,如果值为ALL说明是全表扫描,需要检查索引使用情况。
  • 结合业务场景和上述15种场景,逐一核对SQL语句是否存在对应的问题。

总结

索引失效的原因大多和SQL语句的写法有关,开发过程中需要养成良好的SQL编写习惯,避免在索引字段上做函数、运算、类型转换等操作。当遇到查询性能问题时,优先通过执行计划排查索引使用情况,再对照上述场景调整SQL写法或者索引结构,才能有效提升数据库的查询效率。

SQL索引失效索引优化数据库性能修改时间:2026-06-24 14:19:00

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。