mysql 5.6 升级到 5.7 不需重建索引,但必须执行 mysql_upgrade -s 更新系统表结构和统计信息,否则导致认证失败、sys库缺失等硬故障;查询变慢主因是索引统计信息过期,需手动 analyze table。

MySQL 5.6 升级到 5.7 **不需要重建索引**,物理索引结构(B+Tree 页面格式、键值布局)完全兼容;真正需要干预的是系统表结构和统计信息,不是索引本身。
mysql_upgrade -s 是必须的,不加 -s 会出权限和 sys 库问题
升级后若跳过 mysql_upgrade -s,mysql.user 表仍用 5.6 的字段结构(缺 authentication_string),sys 库根本不存在,SELECT 权限校验直接失败。这不是性能问题,是连不上、查不了、看不见库的硬故障。
常见错误现象:
-
Access denied for user 'xxx'@'%' (using password: YES)—— 实际密码正确,但认证字段未初始化 -
SHOW DATABASES不显示sys,SELECT * FROM sys.schema_table_statistics报错Table doesn't exist - 执行
mysql_upgrade卡在Checking table 'mysql.columns_priv'—— 这是没加-s导致它去扫描所有业务表,应立即中断并重跑带-s的命令
实操建议:
- 启动 5.7 实例后,先用
mysql -uroot -p --socket=...确认能连上 - 立刻执行:
mysql_upgrade -u root -p -s(不要加--force,除非明确提示系统表损坏) - 执行完必须重启
mysqld:systemctl restart mysqld,否则新字段和视图不会加载
索引统计信息过期才是查询变慢的主因,不是索引结构变了
5.6 → 5.7 升级不重置 innodb_stats_auto_recalc 计数器,也不自动触发统计更新。如果升级前长期关闭自动采样、或表被大量写入后没跑过 ANALYZE TABLE,优化器就会基于严重偏差的基数(如把 1000 万行估成 10 万)选错执行计划 —— 这才是“查询慢几十倍”的真实原因。
典型表现:
-
EXPLAIN显示rows估算值比实际小 1–2 个数量级 - 原本走索引的
WHERE created_at > '2025-01-01'变成全表扫描 - 联表查询中驱动表选反,
Using filesort/Using temporary频繁出现
实操建议:
- 检查是否启用自动统计:
SELECT @@innodb_stats_auto_recalc;(8.0+ 默认 ON,5.7 默认 OFF) - 对慢查询日志里高频出现的表显式刷新:
ANALYZE TABLE orders, users, logs_2025; - 避免
ANALYZE TABLE全库执行 —— MyISAM 表会锁表,大 InnoDB 表耗时且无必要
OPTIMIZE TABLE 或 ALTER TABLE ENGINE=InnoDB 在 5.7 中本质是重建,但仅在特定场景才需手动触发
OPTIMIZE TABLE 在 5.7 中等价于 ALTER TABLE t ENGINE=InnoDB,会重建聚簇索引 + 所有二级索引,主要解决三类问题:碎片率高(DATA_FREE 占比 > 20%)、页填充率低(旧版遗留 fill_factor=50)、或想切换 ROW_FORMAT(如从 COMPACT 改 DYNAMIC)。它不是升级必需动作。
容易踩的坑:
-
OPTIMIZE TABLE会锁表(5.7.29+ 支持ALGORITHM=INPLACE仅限部分变更,但重建索引本身仍需排他锁) - 磁盘空间需求翻倍 —— 它需要临时空间存新表,
df -h /var/lib/mysql必须预留 ≥ 当前表大小的空间 - 对亿级表执行可能持续半小时以上,期间写入阻塞,客服电话真会被打爆
替代方案更稳妥:
- 用
pt-online-schema-change在线重建,不锁表(需确保 binlog_format=ROW) - 分区表可逐个
ALTER TABLE t REORGANIZE PARTITION ...,缩小锁范围 - 8.0+ 可建不可见索引测试效果,5.7 则先建冗余索引,同步完成再
DROP原索引
最常被忽略的一点:升级后即使索引结构没变、统计也刷新了,某些 SQL 的执行计划仍可能劣化 —— 比如 5.7 新增的 derived_merge 优化器特性,会让视图或子查询合并逻辑改变,导致本该走索引的查询被迫物化临时表。这时要关掉 SET optimizer_switch='derived_merge=off';,而不是盲目重建索引。











