mysql性能问题70%以上源于索引缺失或低效,需确保where、order by、group by字段被联合索引最左前缀覆盖,避免全表扫描、filesort及函数操作导致索引失效。

索引设计是否覆盖查询条件与排序字段
MySQL 性能问题里,70% 以上和索引缺失或低效有关。不是“加了索引就快”,而是要看 WHERE、ORDER BY、GROUP BY 中用到的列是否被联合索引最左前缀覆盖。
常见错误现象:EXPLAIN 显示 type=ALL(全表扫描)或 Extra 出现 Using filesort / Using temporary。
- 复合索引要按「等值查询列 → 最左前缀 → 范围查询列 → 排序列」顺序组织,例如查询
WHERE a = 1 AND b > 10 ORDER BY c,适合建(a, b, c) -
LIKE以通配符开头(如LIKE '%abc')无法走索引,考虑全文索引或倒排表替代 - 避免对索引列做函数操作,
WHERE YEAR(create_time) = 2024会跳过索引,应改写为create_time BETWEEN '2024-01-01' AND '2024-12-31'
慢查询是否被真正识别和归因
开启慢查询日志只是第一步,关键在于怎么从日志里定位真凶。默认 long_query_time=10 对高并发 OLTP 场景完全没意义,实际应设为 0.1 或更低,并配合 log_queries_not_using_indexes=ON。
使用场景:线上突然出现响应延迟,但监控看不出 CPU/IO 突增——大概率是某条未走索引的查询在积压。
- 用
mysqldumpslow -s t -t 10 /var/lib/mysql/slow.log快速看耗时 Top 10 查询 - 注意区分逻辑读(
Rows_examined)和物理读(磁盘 IO),前者高说明 SQL 写得差,后者高才可能是缓存不足 - 某些 ORM 自动生成的查询带冗余
SELECT *或 N+1,需结合应用层日志交叉验证
InnoDB 缓冲池与刷脏策略是否匹配业务负载
innodb_buffer_pool_size 不是越大越好,也不是简单设为物理内存 70% 就完事。它直接影响数据页缓存命中率,而命中率低于 95% 通常意味着缓冲池不足或查询低效。
性能影响:缓冲池太小 → 频繁磁盘读;太大 → OS 内存压力大,还可能拖慢 MySQL 启动和预热速度。
- 通过
SHOW ENGINE INNODB STATUS\G查看Buffer pool hit rate,或查information_schema.INNODB_BUFFER_POOL_STATS -
innodb_io_capacity和innodb_io_capacity_max要根据磁盘类型调(SSD 建议设为 2000/4000,HDD 则 200/400) - 批量写入场景下,
innodb_flush_log_at_trx_commit=2可显著提升吞吐,但有秒级数据丢失风险,需权衡
执行计划是否被统计信息误导
MySQL 优化器依赖表的统计信息做代价估算,而 ANALYZE TABLE 并不自动触发——尤其在大表批量导入或删除后,旧统计信息会导致优化器选错索引,甚至放弃使用索引。
容易踩的坑:明明有索引,EXPLAIN 却显示 key=NULL;或者同一条 SQL 在不同时间执行计划突变。
- 定期(如每天低峰)对核心大表执行
ANALYZE TABLE t1, t2 - 对行数波动剧烈的表(如日志表),可手动更新统计信息:
ANALYZE TABLE log_202405 WITH SYNC(8.0+ 支持) - 用
optimizer_trace查看优化器决策过程,确认是否因rows估算偏差导致误判
真实线上优化往往卡在“以为改了配置就生效”,其实更常出问题的是索引覆盖不全、统计信息陈旧、以及慢查询背后隐藏的业务逻辑缺陷——比如一个分页接口 LIMIT 1000000, 20,再好的索引也救不了。











