## 症状现象
页面时快时慢,重启数据库能好一阵子,过几天又复发;或者业务量没有明显变化,CPU 却总被数据库占着,top 里 mysqld 一枝独秀。这类问题十有八九出在个别慢 SQL 上,靠猜没有出路,第一步是把慢查询日志打开,让数据库自己交代哪些语句拖了后腿。日志一开,慢的证据、频率、来源地址全在里面,优化不再靠感觉,治理才有依据可循。慢日志同时记录未走索引的查询与锁等待时间,配合应用侧的请求日志对时间点,很容易把某次卡顿对应到具体语句。
## 定位与开启
优先用动态方式开启,不重启实例,业务无感知:
sql SET GLOBAL slow_query_log = ON; SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log'; SET GLOBAL long_query_time = 1;
long_query_time 单位是秒,默认值高达十秒,对 Web 业务来说太宽松,通常先收到 1 秒,稳定后再逐步收紧到 0.5 甚至 0.2。设为 0 会记录全部查询,日志量暴涨,只适合短时间采样找规律。动态变量重启即失,确认策略有效后记得同步写进 my.cnf 的配置段,否则下次维护重启又回到原点。日志文件所在目录要提前建好并把属主交给 mysql 用户,否则开启动作本身会报错。
## 拿到日志先看什么
先别逐条硬读,用自带的 mysqldumpslow 做聚合:
bash mysqldumpslow -s c -t 10 /var/log/mysql/slow.log
-s c 按出现次数排序,-t 10 只取前十名;把 c 换成 t 则按总耗时排序,换成 r 按扫描行数排序。看聚合结果盯三个维度:次数最多的是高频小伤口,加个索引往往立竿见影;单次耗时最长的是大查询,通常是缺分页或一次取太多;扫描行数巨大的多半没走索引。锁定嫌疑语句后,把完整 SQL 拿出来在前面加 EXPLAIN 看执行计划,重点看 type 与 rows 两栏,全表扫描且 rows 以十万计的优先处理。日志里的 Lock_time 一栏也别忽视,锁等待高说明不止慢,还挡了别人。
## 预防建议
把慢日志分析变成例行动作,每周扫一次聚合结果,新功能上线前在测试环境先过一遍执行计划。归档清理老日志,避免它自己把磁盘吃掉。同时在顺云控制台把磁盘 IO 与 CPU 的告警阈值配好,慢查询堆积往往先表现为 IO 上升,告警早响一小时,处理就从容得多。