WHERE name LIKE '%abc' 用不上索引,因为B+树索引需有序匹配,左通配符无法从索引头开始查找,只能全表扫描;仅LIKE 'abc%'等前缀匹配可用普通索引。

为什么 WHERE name LIKE '%abc' 用不上索引
因为 MySQL 的 B+ 树索引是按值排序存储的,LIKE 左侧带通配符('%abc')时,无法从索引头开始有序匹配,优化器直接放弃走索引。不是“没建对”,是根本没法用。
- 只有
LIKE 'abc%'这种前缀匹配才能用上普通索引 -
LIKE '%abc%'或LIKE '%abc'在无函数索引时,一律全表扫描 - 如果字段是
utf8mb4,还可能因字符集校对规则(如utf8mb4_0900_as_cs)让隐式转换进一步破坏索引使用
MySQL 8.0+ 函数索引怎么写才生效
函数索引不是给任意表达式加索引,而是把「计算结果」固化进索引结构里,所以定义和查询必须严格一致。差一个括号、多一个 UPPER()、少一个 TRIM(),索引就失效。
- 建索引:
CREATE INDEX idx_name_lower ON users ((LOWER(name)))—— 注意双括号,这是 MySQL 8.0+ 函数索引语法 - 查数据必须写成:
WHERE LOWER(name) = 'tom',不能写WHERE name = 'TOM'或WHERE UPPER(name) = 'TOM' - 不支持对同一列建多个函数索引(比如同时建
(LOWER(name))和(TRIM(name))),会报错ERROR 3962
ORDER BY RAND() 为什么不能靠索引加速
因为 RAND() 是非确定性函数,每次调用返回不同值,MySQL 无法预计算索引顺序,更没法复用 B+ 树的有序性。哪怕你给字段建了函数索引,RAND() 本身也不在索引表达式里。
-
ORDER BY RAND()强制触发 filesort,且需要为每行生成随机数,IO 和 CPU 开销都大 - 替代方案不是“优化索引”,而是换思路:比如先用
SELECT COUNT(*)拿总数,再应用层生成随机 offset,用LIMIT offset, 1查(注意分页深了也慢) - 如果真要随机抽样且数据量大,考虑用
TABLESAMPLE(MySQL 8.0.23+)或物理分块采样
哪些函数能用在函数索引里,哪些不行
MySQL 对函数索引的支持很保守,只允许「确定性 + 无副作用 + 可被优化器静态分析」的函数。像 NOW()、UUID()、CONNECTION_ID() 这类运行时才知结果的,直接被拒。
- 可用:
LOWER()、TRIM()、SUBSTRING()、COALESCE()、CASE WHEN表达式(不含子查询) - 不可用:
RAND()、SYSDATE()、USER()、任何含子查询或自定义函数(除非显式声明DETERMINISTIC且满足条件) - 建索引时报错
ERROR 3753就是函数不被允许;报ERROR 3962则是表达式太复杂或含禁止成分
函数索引真正难的不是语法,而是查询语句和索引定义之间那层“完全一致”的脆弱契约——漏个空格、换种写法、升级后默认 collation 变了,都可能让索引静默失效。


















