慢在哪一段,
放慢了给你看

线上每一条慢查询,慢镜都录成一段能回放的时间轴。解析、等锁、扫描、回表、排序,逐段摊开;鼠标停在哪一段,就把那一段的现场展开给你。

只读performance_schema,不解析业务字段,不把任何一行数据搬到我们这儿。

回放台探针处方 采样中 · order-prod-01
时间语句耗时
14:02:07SELECT * FROM orders WHERE status = 'paid' ORDER BY create_time DESC3.19s
14:01:52UPDATE stock SET n = n - 1 WHERE sku = 'SK-3271'420ms
14:00:58SELECT COUNT(*) FROM order_item WHERE order_id IN (…)96ms
回放 · orders / 14:02:07 3.19s
等锁 1.94s · 占掉六成 行锁被 #3271 号事务握着,它正在扣库存。
等锁 1.94s 扫描 612ms 回表 排序
00.00 / 03.19

三步装完,之后它自己找上门

不改业务代码,不加中间件。点左边任意一步,右边就切到那一步的真实界面。

探针回放台 manjing-agent · v2.4
$ manjing agent --dsn 'ro@tcp(10.0.3.7:3306)/order_center'
连接成功 · 权限校验通过(SELECT, PROCESS, REPLICATION CLIENT)
已订阅 performance_schema.events_statements_history
阈值取自库上现设的 long_query_time = 0.5s
● 采样中,每 200ms 取一次执行现场
不需要重启数据库,也不需要 root。探针常驻内存有 32MB 的上限,超了自己退出;采到的语句在本机就抹掉字面量,只带走结构和计时。
现场回放台处方 14:02:07 · orders
SELECT * FROM orders WHERE status = 'paid' ORDER BY create_time DESC LIMIT 50;
行锁等待 1.94s 扫描 1.2M 行 Using filesort 走了 idx_status 返回 50 行
#3271 · UPDATE stock 扣减 SK-3271 库存,事务开了 2.1s 未提交
本次查询 · 等待中 排在 orders 主键行锁队列的第 2 位
阻塞链已按事务号串好,点任一环可跳到它自己的回放。
处方回放台 orders · 索引建议
KEY `idx_status` (`status`)
+KEY `idx_status_ctime` (`status`, `create_time` DESC)
预估扫描行数1.2M 3.4K
访问类型ref range
Extrafilesort
复制这段 DDL 在测试库试跑 数字来自执行计划预估,不是实测

把这 3.19 秒摊开

每一段的宽度就是它真实占掉的时间。停在任意一段上,它会展开成那一段的现场。

1 秒
解析 8ms 语句命中了解析树缓存,这一段几乎不用看。
等锁 1.94s 六成的时间都花在这儿:行锁被另一个事务握着,它在扣库存时顺手锁了这批订单。
扫描 612ms 走了 idx_status,可这个状态下的订单本来就多,命中之后还得逐行判断。
回表 331ms 每命中一行就回主键取一次,随机读把磁盘队列排满了。
排序 296ms 排序字段不在索引里,退化成 filesort,只好在内存里重排一遍。
00.00 03.19

现在就能在你自己的从库上跑一遍

装在任意一台能连到从库的机器上,泡杯茶回来,第一段回放大概就录好了。

复制
$ brew install manjing
$ manjing agent --dsn "$MANJING_DSN" \
    --replay on