MySQL 8.0函数索引仅匹配WHERE或ORDER BY中字面完全一致的表达式,需双括号语法、确定性函数,且必须用EXPLAIN验证生效;不支持语义等价推导或隐式转换。

函数索引在 MySQL 8.0 中不是“自动适配任意函数写法”的捷径,它只对 WHERE 或 ORDER BY 中**字面完全一致**的表达式生效;建错语法、写错调用、用错函数,都会导致全表扫描。
CREATE INDEX 必须用双括号包裹表达式
这是硬性语法要求,缺一层括号就报错 ERROR 1064,不是风格问题。
-
CREATE INDEX idx_lower_email ON users ((LOWER(email)));✅ 正确:外层双括号 + 确定性函数 -
CREATE INDEX idx_bad ON users (LOWER(email));❌ 报错:缺最外层括号 -
CREATE INDEX idx_bad2 ON users ((email));❌ 报错:括号内是纯列名,不是表达式 -
CREATE INDEX idx_bad3 ON users ((SUBSTRING(name, 1, 10)));✅ 可用,但注意SUBSTRING()必须显式声明长度,否则可能被拒
WHERE 条件必须逐字符匹配索引定义
优化器不做语义等价推导——多一个空格、换大小写、改函数名、加别名,统统不走索引。
- 建了
((DATE(created_at))),只有WHERE DATE(created_at) = '2026-05-06'能命中 -
WHERE created_at >= '2026-05-06'→ 不走(没包函数) -
WHERE DATE(created_at) >= '2026-05-06'→ 不走(函数索引不支持范围比较) -
WHERE lower(email) = 'a@b.c'→ 不走(建的是UPPER()或大小写不一致) -
WHERE LOWER(email) LIKE 'admin%'→ ✅ 可走(前缀LIKE在函数索引上仍有效)
只能用确定性、无副作用的函数
MySQL 要求表达式每次执行返回相同结果,且不能依赖会话变量、子查询、非固定时区或随机值。
- ✅ 允许:
UPPER()、TRIM()、DATE()、SUBSTRING_INDEX(email, '@', -1)、price * 1.1 - ❌ 禁止:
NOW()、RAND()、UUID()、CONVERT(name USING utf8mb4)、(SELECT COUNT(*) FROM logs) - ⚠️ 高危:
MD5(content)虽确定,但若content很长,结果可能超 3072 字节限制,建索引失败
必须用 EXPLAIN 验证是否真生效
别靠“应该能走”判断,唯一可信依据是 EXPLAIN 输出里的 key 和 Extra 字段。
-
key: idx_lower_email→ 明确使用该函数索引 -
Extra: Using index→ 覆盖索引,无需回表 -
key: NULL或出现Using filesort/Using temporary→ 函数索引未生效 - 常见失效原因:WHERE 写法不一致、用了禁止函数、表达式结果超长、字段类型隐式转换(如数字列和字符串常量比较)
最容易被忽略的是:函数索引不支持任何隐式类型转换或表达式重写,哪怕逻辑等价也不行;它本质上是对“字符串化的 SQL 表达式”做字面匹配,不是对语义做推理。写完索引和查询后,务必跑一遍 EXPLAIN 看 key 是否非空。


















