🏠 首页 攻略 AI 帮你优化 SQL:5 个真实慢查询的提速方案

AI 帮你优化 SQL:5 个真实慢查询的提速方案

数据库越来越慢?别急着加索引。用 AI 分析执行计划,找出真正的性能瓶颈。本文展示 5 个真实慢查询的优化过程,从 30 秒到 200 毫秒。

你的数据库查询越来越慢。

表数据量上去了,索引也加了,但查询还是卡。

这时候别盲目加索引。先让 AI 帮你看看执行计划,找到真正的瓶颈在哪。

我最近用 Claude Code + ChatGPT 分析了 5 个真实的慢查询,效果不错。把整个过程整理出来。

案例一:LIKE ‘%关键词%’ 导致全表扫描

原始查询(耗时 28 秒):

SELECT * FROM products 
WHERE name LIKE '%耳机%' 
   OR description LIKE '%耳机%';

问题很明显:LIKE '%xxx%' 没法用索引,数据库只能全表扫描。

AI 给出的优化方案:

-- 方案 A:使用 PostgreSQL 全文搜索
SELECT * FROM products 
WHERE to_tsvector('simple', name || ' ' || description) 
      @@ to_tsquery('simple', '耳机');
-- 方案 B:如果数据量大,建一个搜索专用表
CREATE TABLE product_search (
    product_id INTEGER REFERENCES products(id),
    search_vector tsvector,
    PRIMARY KEY (product_id)
);

-- 插入数据
INSERT INTO product_search (product_id, search_vector)
SELECT id, to_tsvector('simple', name || ' ' || description)
FROM products;

-- 查询
SELECT p.* FROM products p
JOIN product_search ps ON p.id = ps.product_id
WHERE ps.search_vector @@ to_tsquery('简单', '耳机');

优化后查询时间降到 120 毫秒。快了 230 倍。

案例二:嵌套子查询导致的笛卡尔积

原始查询(耗时 45 秒):

SELECT u.name, 
       (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) as order_count,
       (SELECT SUM(amount) FROM orders o WHERE o.user_id = u.id) as total_spent
FROM users u
WHERE u.created_at > '2025-01-01';

每个用户都要查两次 orders 表,10 万用户就是 20 万次查询。

AI 给出的优化方案:

SELECT u.name, 
       COALESCE(s.order_count, 0) as order_count,
       COALESCE(s.total_spent, 0) as total_spent
FROM users u
LEFT JOIN (
    SELECT user_id, 
           COUNT(*) as order_count, 
           SUM(amount) as total_spent
    FROM orders 
    GROUP BY user_id
) s ON u.id = s.user_id
WHERE u.created_at > '2025-01-01';

把子查询改成 JOIN,一次性聚合所有数据。查询时间降到 800 毫秒

关键技巧:GROUP BY 在子查询里做,外层只做 JOIN。这样数据库可以用一次扫描完成聚合。

案例三:没有分页的大列表查询

原始查询(耗时 15 秒):

SELECT * FROM logs ORDER BY created_at DESC LIMIT 10000 OFFSET 50000;

OFFSET 50000 意味着数据库要先查出 50000 条记录,然后丢弃前 50000 条,只返回最后 10000 条。

AI 给出的优化方案:

-- 方案 A:游标分页(推荐)
SELECT * FROM logs 
WHERE created_at < '上次最后一条的时间戳'
ORDER BY created_at DESC 
LIMIT 100;

-- 方案 B:延迟关联
SELECT l.* FROM logs l
INNER JOIN (
    SELECT id FROM logs 
    ORDER BY created_at DESC 
    LIMIT 100 OFFSET 50000
) AS sub ON l.id = sub.id;

方案 A 用了游标分页,不需要算 OFFSET。方案 B 先用子查询拿到 ID 列表(只扫索引),再回表拿完整数据。

两个方案都降到 200 毫秒以内

案例四:多表 JOIN 缺少合适索引

原始查询(耗时 35 秒):

SELECT o.id, o.total, c.name, p.title
FROM orders o
JOIN customers c ON o.customer_id = c.id
JOIN products p ON o.product_id = p.id
WHERE o.status = 'completed'
  AND o.created_at BETWEEN '2025-01-01' AND '2025-12-31'
  AND c.country = 'CN';

AI 分析执行计划后的建议:

-- orders 表复合索引
CREATE INDEX idx_orders_status_created ON orders(status, created_at) 
INCLUDE (customer_id, product_id, total);

-- customers 表索引
CREATE INDEX idx_customers_country ON customers(country) 
INCLUDE (name, id);

注意 INCLUDE 关键字。它创建的是覆盖索引——查询需要的字段都在索引里,不需要回表。

优化后查询时间降到 300 毫秒

案例五:GROUP BY 后过滤聚合结果

原始查询(耗时 22 秒):

SELECT department, AVG(salary) as avg_salary
FROM employees
WHERE department IN ('技术部', '产品部', '市场部')
GROUP BY department
HAVING AVG(salary) > 15000;

HAVING 在 GROUP BY 之后执行,这意味着先对所有部门分组计算平均值,然后再过滤。

AI 给出的优化方案:

WITH dept_stats AS (
    SELECT department, AVG(salary) as avg_salary
    FROM employees
    WHERE department IN ('技术部', '产品部', '市场部')
    GROUP BY department
)
SELECT department, avg_salary
FROM dept_stats
WHERE avg_salary > 15000;

用 CTE 让查询意图更清晰。虽然在这个例子里性能提升不大(CTE 会被内联),但如果逻辑更复杂,CTE 能让数据库优化器更好地选择执行计划。

实际测试中,加上索引后 HAVING 条件也能走索引过滤,查询降到 500 毫秒

用 AI 分析执行计划的技巧

光知道怎么优化不够,你得会自己发现问题。

方法 1:让 AI 解读 EXPLAIN 输出

EXPLAIN ANALYZE 的结果丢给 Claude 或 ChatGPT:

这是 PostgreSQL 的执行计划,帮我分析哪里慢:
Seq Scan on orders  (cost=0.00..125000.00 rows=5000000 width=48)
  Filter: (status = 'completed' AND created_at >= '2025-01-01')
  Rows Removed by Filter: 4500000
...

AI 会告诉你:Seq Scan 说明没走索引,Filter 去掉 450 万行说明选择性差,建议加复合索引。

方法 2:让 AI 自动生成索引建议

-- 把慢查询发给 AI
-- Prompt: "这个查询很慢,请分析并给出索引建议"

SELECT * FROM users u
JOIN orders o ON u.id = o.user_id
JOIN items i ON o.id = i.order_id
WHERE u.city = '北京'
  AND o.amount > 100
  AND i.category = '电子产品'
ORDER BY o.created_at DESC;

AI 通常会建议:

CREATE INDEX idx_users_city ON users(city) INCLUDE (id);
CREATE INDEX idx_orders_user_amount ON orders(user_id, amount) 
  INCLUDE (id, created_at);
CREATE INDEX idx_items_order_category ON items(order_id, category) 
  INCLUDE (id);

方法 3:定期用 AI 审查慢查询日志

把 MySQL 的 slow_query_log 或 PostgreSQL 的 pg_stat_statements 导出成 CSV,让 AI 分析 Top 20 慢查询,批量给出优化建议。

工具推荐

工具用途费用
Claude Code交互式 SQL 优化API 按量付费
ChatGPT Plus解释执行计划$20/月
ExplainSQL.ai自动 SQL 优化免费额度有限
Perplexity AI搜索最佳实践免费

总结

SQL 优化的核心思路就三条:

  1. 能走索引就别全表扫描
  2. 能 JOIN 就别子查询
  3. 能覆盖就别回表

AI 的作用不是替你写 SQL,而是帮你快速理解执行计划、给出优化方向。真正动手改的还是你。

你的数据库有慢查询吗?把执行计划丢给 AI 试试,看看它能发现什么。