mysql 8.0索引优化核心是代价模型驱动和字面级精确匹配:默认启用cost model择优选索引,函数索引需确定性且定义与查询完全一致,降序索引实现物理有序存储。

MySQL 8.0 的索引优化不是“比 5.7 多几个功能”,而是底层决策逻辑变了——它不再默认走索引,而是算代价;不是“语法支持函数索引”,而是解析器真能认出 (UPPER(name)) 这种写法。升级后执行计划变差?大概率不是 8.0 不行,是你没跑 ANALYZE TABLE。
Cost Model 是否启用决定索引选择逻辑
5.7 的优化器看到 WHERE a = ? AND b > ?,只要 idx_a 存在,就大概率直接选它;8.0 默认启用 Cost Model,会估算用 idx_a、idx_b 或联合索引的 I/O 和 CPU 总成本,再挑最低的。
-
SELECT @@optimizer_switch LIKE '%cost_model=on%'可确认是否启用 - 统计信息陈旧时,Cost Model 会误判——大表升级后务必立即执行
ANALYZE TABLE -
EXPLAIN FORMAT=TREE在 8.0 中可直接看到各节点预估cost值,5.7 不支持 - 调试时可用
SET optimizer_switch='cost_model=off'临时关掉,但生产环境不建议
函数索引在 5.7 和 8.0 中根本不是一个东西
5.7 执行 CREATE INDEX idx ON t ((UPPER(name))) 会直接报错 ERROR 1064 (42000),因为解析器根本不认识括号里的函数表达式;8.0.13+ 才真正支持,且本质是自动创建不可见虚拟列 + 对其建 B+ 树索引。
- 函数必须确定性:
UPPER()、TRIM()可以,NOW()、RAND()直接报ERROR 3905 -
EXPLAIN中key字段显示的是虚拟列名(如func_001),不是你写的函数名 - 只对等值或明确左前缀范围有效:
UPPER(name) = 'ABC'✅,UPPER(name) LIKE '%bc'❌ - 查询中的函数调用必须和索引定义字面完全一致:空格、括号嵌套、大小写都不能差
降序索引从“无效声明”变成“物理有序”
5.7 允许写 INDEX (a DESC, b ASC),但 SHOW CREATE TABLE 会悄悄抹掉 DESC,实际仍是升序;8.0 是叶子节点级物理降序存储,ORDER BY a DESC, b ASC 才能免 Using filesort。
- 命中前提严格:查询的
ORDER BY字段顺序、方向必须与索引定义完全一致 -
WHERE a > 100 ORDER BY a DESC, b ASC可走索引;ORDER BY a DESC, b DESC而索引是(a DESC, b ASC)则不命中 - WHERE 条件需覆盖最左前缀,否则仍可能退化为全索引扫描
- 5.7 下这类索引声明纯属无效,别指望它优化排序
真正容易被忽略的点不在语法层面,而在绑定时机:函数索引和降序索引的匹配发生在 SQL 解析阶段,是字面级精确匹配,不是运行时推导。哪怕多一个空格,或者 UPPER(col) 写成 UPPER( col ),优化器就视而不见。











