MySQL升级后索引统计信息可能过期,导致执行计划劣化
MySQL 5.7 升级到 8.0 或跨大版本迁移(如 5.6 → 8.0)时,
INFORMATION_SCHEMA.STATISTICS和
mysql.innodb_index_stats中的统计信息不会自动重建。优化器依赖这些数据估算行数,一旦失真,可能选错索引甚至走全表扫描。 升级后立即执行
ANALYZE TABLE(对每个关键表),不是“建议”,是必须操作 8.0 默认启用
innodb_stats_auto_recalc=ON,但仅对数据变更超 10% 的表触发;冷迁移后无变更,不会自动更新 若使用
mysqldump导入,导入完成后再
ANALYZE TABLE,不要在导入过程中穿插执行
8.0 的默认排序规则(collation)变更会隐式影响索引匹配
MySQL 8.0 将默认 collation 从
utf8mb4_general_ci改为
utf8mb4_0900_as_cs(大小写敏感、重音敏感)。如果原库字段定义未显式指定 collation,升级后新建索引或 ALTER 表时可能用新规则,导致
WHERE name = 'ABC'无法命中旧索引(因排序规则不一致,优化器判定无法使用)。 检查现有索引字段的 collation:执行
SHOW FULL COLUMNS FROM table_name LIKE 'col_name';,确认
Collation列是否统一 迁移前统一显式声明 collation,例如建表时写
name VARCHAR(64) COLLATE utf8mb4_unicode_ci,避免依赖默认值 升级后用
EXPLAIN FORMAT=TREE查看实际是否用索引;若显示
Using where; Using index消失,优先怀疑 collation 不匹配
函数索引(8.0.13+)在迁移中容易被忽略或误用
如果你在 8.0 环境中创建了函数索引(如
CREATE INDEX idx_email_domain ON users ((SUBSTRING_INDEX(email, '@', -1)));),而目标环境是 5.7 或早期 8.0 版本,
mysqldump会导出语法错误的建表语句,恢复失败。 检查是否用了函数索引:
SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = 'db' AND INDEX_NAME LIKE 'func%';
mysqldump --skip-log-bin --no-tablespaces仍会输出函数索引语法;需手动替换或用
--skip-routines --skip-triggers --skip-events并额外处理索引 函数索引对表达式有严格限制(不能含用户变量、存储函数、非确定性函数),迁移后若查询变慢,先查
SHOW CREATE TABLE是否真建成功,再查
EXPLAIN是否命中
并行查询(8.0.14+)和哈希连接开启后,内存配置不当反而拖慢简单查询
8.0 默认启用
hash_join=ON和
parallel_query=ON(部分版本),对 JOIN 性能提升明显,但会显著增加
join_buffer_size和
cte_max_recursion_depth等内存消耗。小规格实例(如 2C4G)若未调低阈值,简单两表 JOIN 可能因等待并行资源或哈希构建失败而退化为更慢路径。 上线前验证:在测试环境关掉并行和哈希连接(
SET SESSION optimizer_switch='hash_join=off,parallel_query=off';),对比关键查询的
EXPLAIN ANALYZE输出 生产环境若保留开启,务必设置
max_execution_time防止长哈希构建阻塞其他连接 注意
optimizer_switch是会话级变量,应用连接池需在初始化 SQL 中显式关闭,不能只靠全局配置
函数索引语法兼容性、collation 隐式继承、统计信息滞后——这三个点在升级或迁移后最常引发“没改代码,查询突然变慢”的问题,且日志里几乎不报错,只能靠
EXPLAIN和
SHOW CREATE TABLE对比定位。
