一、前言
除了类型转换,另一类高频索引失效问题:对普通索引列做函数、算术运算 ,以及表达式索引使用不规范。

很多开发者为了适配业务查询,习惯在 WHERE 条件中对索引列加工处理,直接导致精心建立的索引彻底作废,是线上慢查询的主要元凶之一。
二、核心开发规范
-
普通索引列,禁止在查询条件中进行任何计算、函数包裹;
-
表达式(函数)索引,查询表达式必须与建索引表达式完全一致,写法不同则无法命中。
三、底层原理通俗讲解
-
普通B+树索引 :仅存储字段原始值,数据库无法对加工后的值匹配索引,一旦索引列参与运算,只能全表扫描;
-
表达式索引:存储的是「函数/运算后的结果值」,仅能匹配完全相同的表达式,细微写法差异都会导致索引失效。
四、实战错误案例&优化方案
场景1:普通索引列使用函数(最高频错误)
表设计:bill 表 create_time 为 datetime 类型,建有普通单列索引。
❌ 错误写法(索引列套函数,索引失效)
sql
SELECT * FROM bill WHERE DATE(create_time) = '2026-09-10';
✅ 正确优化写法(计算转移到常量侧,保留索引列原生形态)
sql
SELECT * FROM bill WHERE create_time >= '2026-09-10 00:00:00' AND create_time < '2026-09-11 00:00:00';
场景2:普通索引列做算术运算
表设计:bill 表 amount 建有普通索引。
❌ 错误写法(索引列参与运算)
sql
SELECT * FROM bill WHERE amount + 100 = 2000;
✅ 正确写法(常量侧运算,索引列无加工)
sql
SELECT * FROM bill WHERE amount = 1900;
场景3:表达式索引写法不匹配,无法命中
第一步:创建表达式索引
sql
CREATE INDEX idx_expr_bill_date ON bill ((DATE(create_time)));
✅ 正确写法(表达式完全一致,正常命中索引)
sql
SELECT * FROM bill WHERE DATE(create_time) = '2026-09-10';
❌ 错误写法(函数写法变更,索引失效)
sql
SELECT * FROM bill WHERE CAST(create_time AS DATE) = '2026-09-10';
关键结论 :函数索引对写法完全敏感,函数名、参数、顺序必须和建索引语句一模一样。
五、绝对禁止的写法汇总
-
索引列 + 函数:
DATE(col)、SUBSTR(col)、UPPER(col) -
索引列 + 算术运算:
col+N、col-N、col*N、col/N -
表达式索引,查询表达式与建索引表达式不一致
六、最终评审口诀(记住不踩坑)
普通索引列不动,计算全放常量中;
函数索引严匹配,写法错乱索引空。
七、总结
索引失效绝大多数不是索引没建对,而是SQL写法不规范。开发和评审时,只要守住「类型一致、索引列不运算、函数索引严匹配」三条底线,就能规避99%的线上索引失效、慢查询性能问题。