mysql性能调优应先分析慢查询日志,确认拖慢系统的sql;再用explain评估执行计划,针对性优化索引;最后根据缓冲池实际命中率和磁盘读频率决定是否调整innodb_buffer_pool_size。

先看慢查询日志,别急着调参数
MySQL性能调优的第一步不是改innodb_buffer_pool_size,也不是加索引,而是确认“到底哪些SQL在拖慢系统”。很多团队一上来就调大缓冲池、换SSD、升级CPU,结果发现90%的延迟来自一条没走索引的select *全表扫描。
实操建议:
- 用
show variables like 'slow_query_log';确认是否开启;没开就执行set global slow_query_log = 1; - 把
long_query_time设为1秒(set global long_query_time = 1;),比默认10秒更早暴露问题 - 日志输出建议设为
FILE(set global log_output = 'FILE';),避免写入mysql.slow_log表带来额外开销 - 用
mysqldumpslow -s t -t 10 /var/lib/mysql/slow.log快速找出耗时TOP10的SQL
用EXPLAIN看执行计划,而不是猜索引有没有用
看到慢SQL后,别直接建索引。先跑一遍EXPLAIN,否则极容易建错索引——比如给WHERE a = ? AND b IN (?, ?) ORDER BY c建了(a)单列索引,实际需要的是(a, b, c)联合索引。
重点关注三项:
-
type:从ALL(全表扫描)→range→ref→const是优化方向;如果还是ALL,说明没走索引或索引失效 -
rows:预估扫描行数,和实际数据量差距过大(比如表有10万行,rows=98234),大概率没利用好索引选择性 -
Extra里出现using filesort或Using temporary,意味着排序/分组没走索引,必须干预
调innodb_buffer_pool_size前,先验证内存是否真够用
盲目把innodb_buffer_pool_size设成物理内存70%,可能反而引发OS频繁swap——尤其当服务器还跑着Java应用或redis时。真正该看的是InnoDB缓冲池的“水位”是否健康。
执行SHOW GLOBAL STATUS LIKE 'innodb_buffer_pool_pages_%';后关注两个数字:
-
Innodb_buffer_pool_pages_free≈ 0?说明缓冲池长期打满,但不等于“足够大”——得结合Innodb_buffer_pool_reads(磁盘读次数)判断:如果该值持续 > 100/秒,说明频繁回磁盘,才真需要扩容 -
Innodb_buffer_pool_read_requests÷Innodb_buffer_pool_reads - 注意:重启MySQL后
pages_free会重置,要等业务流量稳定后再观察
转换MyISAM表到InnoDB时,小心ALTER table ... ENGINE=InnoDB锁表
线上大表执行ALTER TABLE t ENGINE=InnoDB会全程锁表(尤其MySQL 5.6及之前),业务高峰期执行等于主动停服。这不是“要不要转”的问题,而是“怎么转才不伤业务”。
安全做法:
- 对500MB以上表,优先用
pt-online-schema-change(Percona Toolkit),它通过触发器+影子表实现无锁变更 - 若只能用原生命令,务必在低峰期执行,并提前用
SELECT count(*)确认表大小;千万避开mysqldump + DROP + IMPORT这种“先清空再重建”的方式——期间数据完全不可用 - 转换后检查
innodb_file_per_table=1是否生效,否则所有表数据仍挤在ibdata1里,后续无法单独收缩某张表空间
真正的调优起点从来不在配置文件里,而在每条被EXPLAIN戳穿的SQL和每份被mysqldumpslow揪出的慢日志中。最容易被忽略的,其实是“没查慢日志就调参”和“没看rows就建索引”这两件事。