1. 巡检事件 dballgts01e19-2 的第一个线索:慢查询不是偶发而是规则性翻车
晚上 22 点 17 分,告警平台弹出一条由巡检模块自动生成的事件编号:dballgts01e19-2。这种编号第一眼像乱码,但读多了就有规律:db 表示数据库组件,all 表示全链路检查,后面的 gts01e19-2 是时间窗口加批次号。它没有对应的用户投诉工单,说明不是交易主链路炸了,而是某个数据库请求已经连续一段时间超过慢查询红线。
再往前翻监控,业务侧的现象很清楚:商家后台里“订单查询”页接口的 P99 从平时的 600ms 涨到了 3.2s,单量没有明显波动,数据库 CPU 也不高,没有锁等待,没有连接数打满。这种表现最容易让人误判成“网络问题”或者“第三方服务抖动”,但巡检模块既然把前缀打成了 db,问题大概率还是在 MySQL 这一层。
我在慢查询日志里找到了对应的语句,形态大概是这样:
sql复制SELECT id, merchant_id, order_no, pay_amount, order_status, create_time
FROM t_order
WHERE merchant_id = 899001
AND order_status = 2
AND create_time >= '2024-06-01 00:00:00'
AND create_time < '2024-06-30 00:00:00'
ORDER BY create_time DESC
LIMIT 20 OFFSET 0;
这是一条很典型的“商户端订单列表”查询:商户登录后只看自己的订单,按时间倒序分页。order_status = 2 表示只查已支付状态,create_time 限制在一个月内。从业务逻辑看,它不复杂。
表 t_order 当时的规模是 3180 万行,InnoDB 存储引擎,单表数据量在 70GB 左右。表上已有的索引包括主键 id、idx_merchant_id(merchant_id) 和 idx_create_time(create_time)。看到这里,很多人第一反应就是加索引,但我建议先把“为什么这么慢”查清楚,再动手。
1.1 巡检编号为什么能直接定位到数据库
dballgts01e19-2 中的 gts 不是某个中间件名称,而是巡检平台自动生成的时间戳序列。它出现一次,意味着巡检任务在 1 到 1.5 秒的采样窗口里发现这条 SQL 执行了比较长的时间。
第一次定位时,不要只盯一条 SQL。要先问三个问题:慢查询是不是只在高峰期出现?是不是某个商户的订单量异常大?是不是最近上线改过代码或者索引?这三个问题决定了后续优化的方向。
回到这个 case:巡检开始时,慢查询日志里每分钟有 20 到 40 条类似 SQL,而且都集中在 merchant_id = 899001 和几个大商户上。显然不是偶发,是同一类查询在高峰期稳定变慢。
1.2 查询代码里的“分页参数”成了噪音
这里有个容易被忽略的细节:代码里实际传入的 create_time 范围是根据页面上的默认筛选条件拼出来的。如果用户没有手动选时间,前端会默认传最近一个月。一个月对中小商户来说可能只有几千条订单,但对 899001 这种高量级商户来说,单月订单量接近 6 万多条,再加上 order_status 过滤,一次查询要处理的数据量完全不同。
也就是说,这条 SQL 不是“每页都慢”,而是“大商户 + 默认大时间范围”才慢。优化前必须把这个条件固定下来,否则你在测试环境只拿一个 1000 行的小表验证,永远复现不了生产问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 先别急着加索引:我是按这四步把问题现场还原出来的
一旦确认是慢查询,很多同学会直接执行 EXPLAIN,看一眼 possible_keys 和 key 就开始写 ALTER TABLE。但执行计划只能反映优化器
