乐于分享
好东西不私藏

把慢查询日志扔给AI,从8秒干到120毫秒

把慢查询日志扔给AI,从8秒干到120毫秒

凌晨3点,手机告警震醒。

某支付系统对账接口响应时间飙到8秒,数据库CPU打满。定位到一条看起来人畜无害的SQL:

SELECT t.order_id, t.tx_id, t.amount, t.status, t.created_at,
       o.merchant_id, o.user_id,
       r.refund_amount, r.refund_reason
FROM transactions t
LEFTJOIN orders o ON t.order_id = o.id
LEFTJOIN refunds r ON t.order_id = r.order_id
WHERE t.status IN ('SUCCESS','FAILED','PROCESSING')
AND t.created_at >= '2026-04-01'
AND t.created_at < '2026-05-01'
ORDERBY t.created_at DESC
LIMIT50;

EXPLAIN一看,倒吸一口气:

表
type
rows
Extra
transactions
ALL
14,832,451
Using where; Using filesort
orders
eq_ref
1
refunds
ALL
6,241,783
Using where

transactions 表 1400 万行全表扫描,refunds 表 600 万行也没走索引。

搁以前,翻文档、看索引、改SQL、测试、上线,一套下来至少半天。这次让AI参与进来。


🔍 第一步:把诊断信息喂给AI

EXPLAIN输出和表结构直接丢给GPT,三个问题:

你是一位资深 MySQL DBA。下面是一条慢查询的 EXPLAIN 结果和表结构。

transactions 约1400万行,orders 约50万行,refunds 约600万行。

请分析:

  1. 为什么两个表走了全表扫描?
  2. 建议创建哪些索引(给出精确 DDL)?
  3. SQL 本身是否可以改写?

诊断结果:

transactions 表: 已有 idx_status 和 idx_created_at 两个单列索引,但查询同时用了 status IN(...) 和 created_at 范围条件——优化器只能二选一。选哪个过滤后都剩大量数据,干脆全表扫描。

refunds 表:idx_order_id 存在,但不包含查询需要的 refund_amount 和 refund_reason。回表开销太大,优化器觉得不如直接扫全表。

根因一句话:联合索引缺失。


🔧 第二步:让AI给索引DDL

AI给出的索引:

-- transactions:覆盖索引
ALTERTABLE transactions ADDINDEX idx_status_created
    (status, created_at, order_id, tx_id, amount);

-- refunds:覆盖索引
ALTERTABLE refunds ADDINDEX idx_order_id_covering
    (order_id, refund_amount, refund_reason);

查询需要的所有列都塞进索引了——覆盖索引,完全避免回表。

⚠️ 但AI不会告诉你:1400万行的表加5列索引,锁多久?占多少磁盘?

自己验证:索引约450MB,可接受。生产环境是 PolarDB,ALGORITHM=INSTANT 秒级完成:

ALTERTABLE transactions
ADDINDEX idx_status_created_cover (status, created_at, order_id, tx_id, amount),
  ALGORITHM=INSTANT;

原则:AI出方案,人做安全校验。


✍️ 第三步:SQL改写

索引加完,rows降到28万,还不够。AI提到一个关键点——用延迟关联改写:

-- 子查询只取 transactions 自己的列,利用覆盖索引完成排序和 LIMIT
SELECT t.order_id, t.tx_id, t.amount, t.status, t.created_at,
       o.merchant_id, o.user_id,
       r.refund_amount, r.refund_reason
FROM (
SELECT order_id, tx_id, amount, status, created_at
FROM transactions
WHEREstatusIN ('SUCCESS','FAILED','PROCESSING')
AND created_at >= '2026-04-01'
AND created_at < '2026-05-01'
ORDERBY created_at DESC
LIMIT50
) t
LEFTJOIN orders o ON t.order_id = o.id
LEFTJOIN refunds r ON t.order_id = r.order_id
ORDERBY t.created_at DESC;

子查询利用覆盖索引直接完成排序+LIMIT,不回表。外层JOIN只关联50行。

新执行计划:

表
type
rows
Extra
transactions
range
286,512
Using where; Using index
orders
eq_ref
1
refunds
ref
3
Using where

refunds 从全表扫描 600 万行 → ref 只扫 3 行。


📊 验证结果

[原SQL]      返回 50 行,耗时 7.8921 秒
[优化后SQL]   返回 50 行,耗时 0.1187 秒
✅ 结果集一致
加速比: 66.5x

上线后对账接口 P99 从 8 秒降到 150 毫秒以内,数据库 CPU 降了约 15%。


📋 慢查询优化模板

每次遇到慢查询,直接套这个 Prompt:

你是 MySQL 优化专家。以下是慢查询的诊断信息。

请严格按顺序回答:

  1. 指出当前执行计划的瓶颈(哪个步骤最耗时、为什么)
  2. 给出索引优化建议(精确DDL),说明设计理由
  3. 给出SQL改写建议(如有必要),写出优化后SQL
  4. 预估优化效果

配合三样东西喂进去:

📄 慢 SQL 原文 

📄 EXPLAIN 输出(JSON 格式最好) 

📄 表结构(SHOW CREATE TABLE)


⚠️ 三个重要提醒

① 不要把生产数据发给AI。 只发表结构、索引、EXPLAIN。真实数据行不要贴,安全第一。

② AI的输出必须自己验证。 它有时会过度设计——比如建议8列覆盖索引。能加速查询,但严重拖慢写入、吃内存。结合业务读写比例判断,别无脑执行。

③ 让AI校验AI。 SQL改写不放心的话,另开一个对话,把原始SQL和改写后的SQL一起发给AI,让它对比两个SQL是否逻辑等价、指出所有可能的语义差异。交叉验证比单次输出靠谱得多。


这套流程第一次跑通后,后面每次都能复用。不是AI替代DBA,是把人从查文档、猜方案、翻手册的循环里解放出来,把精力花在决策上。

GPT-5.6(ai.onewu.work)完全够用,EXPLAIN输出和建表语句丢进去,按模板走。

有踩过慢查询坑的,进群聊聊 👇


相关学习资料