已采纳
回答正文
回复
讨论正文
该问题的正文与回答。
背景
我负责一套 MySQL 8.0.32 / InnoDB 的核心库(单主 32C128G,buffer pool 48G,核心表 2 亿行级别)。慢查询治理是每周例行动作,阈值 slow_query_time=0.5s。最近一个月慢日志量从日均 300 条涨到 2000+ 条,我肉眼扫了一遍,发现一个反复出现的困惑:慢日志里既混着上周新上线接口带来的新 SQL(以前从没出现过),也混着跑了两年、一直 20ms 的老 SQL 最近变成 800ms(digest 早存在,只是变慢了)。这两类的治理动作完全不同——前者该找开发改 SQL / 加索引,后者八成是数据增长或统计信息漂移,得先量化退化幅度再决定动作。但慢日志本身不给我这个分类。
现象
performance_schema.events_statements_summary_by_digest 里,新 SQL 和退化 SQL 的 count_star、avg_timer_wait 看起来都合理,但 first_seen / last_seen 两个字段我一度用 last_seen 判「新增」,结果发现退化 SQL 的 last_seen 也在持续刷新,根本分不开;rows_examined 从 1 万涨到 40 万(上游业务数据量涨了 40 倍),EXPLAIN 还是走同一个索引,只是 rows 估算值大了——这类「数据增长型退化」和「计划漂移型退化」在慢日志里长得一模一样;已尝试的排查
pt-query-digest --group-by=digest 聚合后按 avg_time 排序:能看出哪些 digest 慢了,但分不清「新」还是「退化」,也看不出退化是数据量还是计划问题;performance_schema 的 first_seen / last_seen 字段:first_seen 是 digest 首次出现的时刻,理论上可以区分「新增」(first_seen 在窗口内)和「退化」(first_seen 在窗口外),但退化 SQL 的 avg 耗时是累计平均——一条 SQL 历史上跑过 100 万次、最近 100 次变慢,avg_timer_wait 只从 20ms 涨到 21ms,根本看不出退化,需要自己算「最近 N 次的均值 vs 历史均值」,但 events_statements_summary_by_digest 里没有分时间窗的耗时分布;期望得到的答案形态
events_statements_summary_by_digest 的字段(first_seen / last_seen / count_star / avg_timer_wait / sum_timer_wait),如何区分「新增慢 SQL」(digest 在巡检窗口内首次出现)和「存量 SQL 退化」(digest 早已存在,但近期耗时显著上升)?「显著上升」的阈值怎么定?(比如:最近 1 小时均值 > 历史 7 天均值的 3 倍?)performance_schema 里有没有字段能直接看出「计划变了」(比如 rows_examined_per_fetch 的变化)?还是需要自己抓 EXPLAIN 的 fingerprint 比对?