mysql 8.0索引能力从列级静态升级为表达式级动态,需严格满足stored生成列、双括号语法、表达式逐字符一致等条件,否则索引失效且性能反降。

STORED、WHERE 条件多套一层函数,8.0 的索引就直接失效,而 5.7 压根不会报错,只会默默全表扫描。
为什么 5.7 的 data->>'$.status' 查询不走索引
5.7 不支持函数索引,data->>'$.status' 这种表达式无法被优化器映射到 B+ 树上。哪怕你建了生成列,也必须同时满足两个硬性条件才可能间接生效:
-
GENERATED COLUMN必须是STORED类型(VIRTUAL不可索引) - 查询中写的表达式必须和生成列定义**逐字符一致**:比如
JSON_UNQUOTE(JSON_EXTRACT(data, '$.status'))和data->>'$.status'语义等价,但 5.7 不识别,索引不会被选中 - 一旦加了
UPPER()、TRIM()等任意包装,整个条件就脱离索引能力范围
8.0 的函数索引怎么写才真正生效
8.0 支持原生函数索引,但语法和语义约束极严:
- 必须用双层括号:
CREATE INDEX idx_user_status ON users ((data->>'$.status'))—— 外层是语法必需,内层才是表达式 - 不能直接对函数建索引:
CREATE INDEX ... ON t1(UPPER(name))会报错ERROR 3753 - 必须先建
STORED生成列,再对其建普通索引;或直接用上述双括号语法一步到位 - WHERE 条件必须严格匹配索引表达式,连空格、括号都不能多或少
降序索引在 ORDER BY 混合方向时的表现差异
5.7 对 ORDER BY uid DESC, sid ASC 这类混合排序无解,组合索引一律按升序存储,只能触发 Using filesort;8.0 则可真实创建降序索引:
-
CREATE INDEX idx_uid_desc_sid_asc ON t1 (uid DESC, sid ASC)在 8.0 中有效,在 5.7 中会被忽略为(uid ASC, sid ASC) - 8.0 的降序索引能消除
filesort,前提是ORDER BY方向与索引定义完全一致 - 5.7 即使单字段
ORDER BY x DESC,也能用升序索引做反向扫描(性能略差但可用);8.0 默认启用正向/反向双向扫描优化,实际性能反而更稳
不可见索引和子查询物化对执行计划的真实影响
不可见索引不是“禁用”,而是让优化器默认跳过它,但后台仍在维护;子查询物化也不是自动发生,必须靠提示或结构改写才能触发:
-
ALTER TABLE t1 ALTER INDEX idx_name INVISIBLE后,FORCE INDEX(idx_name)仍无效,必须开启use_invisible_indexes=on才能在 EXPLAIN 中看到它被考虑 -
/*+ MATERIALIZE */提示只对 FROM 子句中的子查询有效(如LATERAL),SELECT 列表里的标量子查询(SELECT (SELECT ...))仍不会物化 - 验证是否真物化,唯一方式是看
EXPLAIN FORMAT=TREE输出里有没有materialize节点,而不是只看有没有DEPENDENT SUBQUERY
STORED、双括号、表达式一致性、MATERIALIZE 提示的适用位置——这些细节一错,性能可能比 5.7 更差,因为多了额外解析开销却没换来索引收益。











