mysql函数索引仅支持确定性且非null安全的内置函数,如upper()、substring()、crc32()等;now()、rand()、uuid()等非确定性函数建索引会直接报错,且表达式结果为null时该行无法被索引命中。

函数索引只支持确定性、非NULL安全的内置函数
MySQL 8.0 的函数索引不是所有函数都能用,CRC32()、MD5()、SHA2()、SUBSTRING()、UPPER()、LOWER() 这类确定性函数可以;但 NOW()、RAND()、UUID()、USER() 等带运行时上下文或非确定性的函数会被直接拒绝建索引,报错 ER_FUNCTION_IS_NOT_ALLOWED_IN_INDEX。
另外要注意:函数表达式结果不能为 NULL,否则该行无法被索引命中。比如 SUBSTRING(email, 1, LOCATE('@', email) - 1) 在 email 不含 @ 时返回 NULL,这部分数据就查不到索引路径。
- 建索引前先验证表达式是否全量可计算:
SELECT COUNT(*), COUNT(expr) FROM t;,若两者不等,说明有 NULL 风险 - 用
COALESCE()或IFNULL()包裹兜底,例如:COALESCE(SUBSTRING(email, 1, LOCATE('@', email)-1), '') - 避免嵌套过深的函数调用,MySQL 对表达式解析深度有限制,超过会报
ER_TOO_BIG_SELECT类错误
WHERE 条件必须严格匹配函数索引定义的表达式
函数索引不会自动“识别语义等价”。比如你建了 CREATE INDEX idx_upper_name ON users (UPPER(name));,那么只有 WHERE UPPER(name) = 'JOHN' 能走索引;而 WHERE name = 'john' 或 WHERE LOWER(name) = 'john' 都不会命中 —— 优化器不会反向推导函数逆运算。
常见误用场景:
- 应用层做了
UPPER()处理再传参,但 SQL 写成WHERE name = ?→ 白建索引 - 用了
LIKE包裹函数结果,如UPPER(name) LIKE 'JO%'→ 可能走索引,但name LIKE 'jo%'绝对不走 - 联合函数索引中混用不同函数,如
(UPPER(last_name), YEAR(birth_date)),查询必须同时按这个顺序和函数形式写条件
函数索引的 key_len 和执行计划要手动验证
函数索引在 EXPLAIN 中显示为普通索引名,但 key_len 值反映的是函数输出结果的字节长度(不是原始列),容易误判。比如 UPPER(varchar(100)) 实际最多占 100 字节(utf8mb4 下是 400 字节),但 key_len 显示的是计算后值的存储长度,不是原列长度。
验证是否真走索引最可靠的方式是:
- 加
FORCE INDEX强制走函数索引,对比EXPLAIN FORMAT=JSON中的used_columns和key_parts - 用
sys.schema_unused_indexes查看该索引是否长期selects = 0 - 在低峰期开启
optimizer_trace,确认优化器是否选择了该索引路径
TEXT/BLOB 列上建函数索引需搭配前缀长度控制
对 TEXT 或 BLOB 列直接建函数索引会失败,因为 MySQL 要求索引键值长度明确。即使你写 SUBSTRING(content, 1, 100),也得显式声明长度限制:
CREATE INDEX idx_first100 ON articles (SUBSTRING(content, 1, 100));
但注意:这实际等价于 SUBSTRING(content, 1, 100) 作为表达式,其隐含长度上限由函数参数决定,而非列定义。如果 content 是 TEXT,SUBSTRING 返回的是 VARSTRING,最大长度取参数第二位(100),所以没问题;但如果写成 SUBSTRING(content, 1)(缺长度),MySQL 会报错 ER_WRONG_FIELD_WITH_GROUP。
更隐蔽的问题是排序规则(collation)继承:函数索引默认使用列的 collation,但若函数改变了字符集(如 CONVERT(... USING utf8mb3)),可能引发隐式转换,导致索引失效。
真正难调试的是函数索引和覆盖索引的组合效果 —— 它们不天然兼容。即使你写了 SELECT UPPER(name) FROM users WHERE UPPER(name) = ?,若没把 UPPER(name) 单独作为索引列包含进去,还是可能回表。这点很容易被忽略。











