先把show full processlist的全量输出存成本地文件,把慢查询日志里最近1小时的条目导出来,甚至要把当时的服务器负载、磁盘IO、连接数这些指标截图存好。 MySQL慢查询日志实时监控告警界面 很多人上来就清缓存、kill进程、改配置,等现场破坏完了,根本不知道当时到底是哪条查询拖垮了数据库。我上次碰到个运维同事,碰到CPU高直接把数据库重启了,重启完啥日志都没留,过了三天同样的问题又犯,折腾了整整一个通宵才找到是个没加索引的报表查询在跑。 所有的排查动作,都要建立在完整的现场证据上,没有证据的操作本质上就是瞎碰运气。 别一看到慢查询就说数据库不行,很多时候是业务侧的问题,比如大促的时候本来流量就高,再加个没做好缓存的查询,直接就把连接占满了。
别迷信加索引就能解决所有问题
拿到慢查询的条目,第一反应很多人就是跑explain,看到type列是ALL,就喊着要加索引。加完跑一遍,好像是快了点,过两天数据涨了,又慢回去了。 MySQL执行计划explain结果截图 我上个月碰到个很典型的例子:订单表上的查询,where条件是create_time > ‘2024-09-01’ and status = 1,开发同学给user_id字段加了个普通索引,执行计划里显示确实用到了这个索引,但是rows列估算的扫描行数是120万,实际跑下来要11秒。为啥?因为表的统计信息停在三个月前,优化器误以为走user_id索引的成本更低,根本没走建在create_time上的联合索引。 这种情况你加再多索引都没用,先跑一句analyze table order_info把统计信息更新了,再看执行计划,直接走对索引,查询耗时从11秒降到80ms。 看执行计划不能只看“有没有用到索引”,重点看rows估算值和实际扫描行数的偏差,偏差超过一个数量级的,先更新统计信息,别上来就改代码。 还有那种最离谱的模糊查询,select * from user where name like ‘%张’,这种查询你加什么索引都白搭,前导模糊查询天生没法走B树索引,要么改业务逻辑用全文索引,要么提前把匹配结果存到缓存里,别硬往数据库上怼。