写在前面
数据库性能问题有一个令人沮丧的特点:在数据量小的时候,代码完全跑得通,没有任何问题;等到数据量上去了,突然各种接口开始变慢,DBA或运维发过来一堆慢查询日志,你看着那些执行计划和EXPLAIN输出,一头雾水。
SQL优化是门需要经验积累的学问——知道该加什么索引、怎么改写子查询、什么时候用临时表、EXPLAIN输出里每个字段什么含义——这些东西不靠刷题,靠的是见过足够多的案例。
Claude 4.6把这个过程压缩了很多。它见过大量的SQL优化案例,可以直接告诉你这个查询慢在哪、该怎么改。
基本用法:粘贴慢查询,问为什么慢
最直接的用法:把慢查询和执行计划一起粘贴给Claude。
这个SQL查询在数据量大时非常慢(10万条数据时需要8秒):
SELECT
o.id,
o.created_at,
u.name as user_name,
u.email,
COUNT(oi.id) as item_count,
SUM(oi.quantity * oi.unit_price) as total_amount
FROM orders o
JOIN users u ON o.user_id = u.id
JOIN order_items oi ON o.id = oi.order_id
WHERE
o.status = 'completed'
AND o.created_at >= '2025-01-01'
AND o.created_at < '2026-01-01'
GROUP BY o.id, o.created_at, u.name, u.email
ORDER BY o.created_at DESC
LIMIT 20 OFFSET 1000;
EXPLAIN ANALYZE输出:
[粘贴EXPLAIN ANALYZE输出]
表结构:
[粘贴CREATE TABLE语句]
请分析:
1. 这个查询慢在哪里(从EXPLAIN里能看出什么)
2. 建议加什么索引,为什么
3. SQL本身有没有可以改写的地方
4. OFFSET分页在这里会有什么问题,如何改成cursor-based分页
读懂EXPLAIN输出
很多人看到EXPLAIN ANALYZE的输出就头大,因为信息量太大、缩进关系复杂。让Claude帮你解读:
请帮我解读这个PostgreSQL的EXPLAIN ANALYZE输出,
重点说明:
1. 哪一步是性能瓶颈(cost最高、actual time最长的节点)
2. 有没有出现Sequential Scan(全表扫描),为什么
3. rows估算和actual rows差距大的地方(说明统计信息不准)
4. 用一句话总结这个查询的主要问题
[粘贴EXPLAIN ANALYZE输出]
Claude会用你能看懂的语言解释,而不是把文档原文粘回来。
索引设计的系统方法
不要等慢查询出现才想着加索引,在设计表结构时就应该考虑。
这是我设计的订单表,帮我分析索引策略:
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
status VARCHAR(20) NOT NULL,
total_amount DECIMAL(12,2),
payment_method VARCHAR(20),
shipping_address_id BIGINT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
paid_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ
);
主要查询场景:
1. 查询某个用户的所有订单(按时间倒序)
2. 按状态筛选订单(后台管理)
3. 按状态+时间范围查询(日报表)
4. 查找某个时间段内完成的订单(用于计算GMV)
请给出:
1. 应该建哪些索引(单列/复合索引)
2. 每个索引覆盖哪些查询场景
3. 哪些索引可以合并(避免冗余)
4. 有哪些索引看起来有用但实际帮助不大,不建议加
Claude的典型输出会帮你区分”必须加”、”有条件加”、”不用加”的索引,并解释复合索引的列顺序为什么重要。
常见慢查询场景
场景一:N+1查询
我发现一个接口每次请求会触发大量数据库查询:
接口:GET /api/orders(订单列表)
每次请求触发SQL数量:1 + N(N为订单数量)
原来的代码:
orders = SELECT * FROM orders LIMIT 20;
for order in orders:
order.user = SELECT * FROM users WHERE id = order.user_id
order.item_count = SELECT COUNT(*) FROM order_items WHERE order_id = order.id
请给出:
1. 改成1-2次查询的方案
2. 对应的SQL语句
3. 如何在后端代码里把查询结果拼装回来
场景二:分页查询性能
我们的订单列表接口用OFFSET分页,在翻到第100页(OFFSET 2000)时明显变慢。
当前的分页SQL:
SELECT * FROM orders
WHERE user_id = 123
ORDER BY created_at DESC
LIMIT 20 OFFSET 2000;
请解释为什么OFFSET在大offset时会慢,
并给出cursor-based分页的改写方案(用last_id或created_at作为cursor)。
场景三:子查询 vs JOIN
这两个SQL实现相同的功能,但性能差距很大:
方法一(子查询):
SELECT * FROM users
WHERE id IN (
SELECT DISTINCT user_id FROM orders
WHERE created_at >= '2025-01-01'
);
方法二(JOIN):
SELECT DISTINCT u.* FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.created_at >= '2025-01-01';
请解释:
1. 哪个方法在大数据量下更快,为什么
2. 是否有第三种更好的写法(比如EXISTS)
3. 数据库优化器会自动处理这种差异吗
场景四:统计查询优化
这个月报统计查询在数据量大时需要30秒以上:
SELECT
DATE_TRUNC('day', created_at) as date,
COUNT(*) as order_count,
SUM(total_amount) as revenue,
COUNT(DISTINCT user_id) as unique_buyers
FROM orders
WHERE created_at >= '2025-01-01' AND created_at < '2026-01-01'
AND status = 'completed'
GROUP BY DATE_TRUNC('day', created_at)
ORDER BY date;
有什么优化方案?
(可以考虑:索引、物化视图、预计算汇总表等方案)
数据库设计问题的诊断
有时候查询慢不只是索引的问题,而是设计有缺陷:
我有个字段设计问题想请你分析:
订单状态(status)字段,目前存储的是字符串:
'pending_payment', 'paid', 'shipped', 'completed', 'cancelled'
另一个开发者建议改成整数枚举(1, 2, 3, 4, 5),说会更快。
请分析:
1. 字符串 vs 整数枚举在这个场景下的实际性能差异大吗
2. 各自的优缺点是什么
3. PostgreSQL的原生enum类型是更好的选择吗
4. 如果要迁移,怎么做最安全(已有数据量500万行)
慢查询监控配置
除了被动排查,主动监控也很重要:
帮我给出PostgreSQL的慢查询监控配置:
目标:
- 记录执行时间超过1秒的查询
- 记录全表扫描(超过10万行)
- 每天生成慢查询报告
请给出:
1. postgresql.conf的相关配置项
2. 如何查看pg_stat_statements收集的慢查询
3. 一个简单的Shell脚本,每天把最慢的20个查询发送到运维邮件
MySQL vs PostgreSQL的差异
如果你在两个数据库之间迁移,让Claude帮你识别差异:
我们要把这个MySQL查询迁移到PostgreSQL,请指出:
1. 语法差异(MySQL特有的函数、字符串拼接等)
2. 行为差异(NULL处理、默认值、事务行为等)
3. 索引和性能方面的差异
4. 改写后的PostgreSQL版本
原始MySQL查询:
[粘贴SQL]
如何用上Claude 4.6
对于日常的SQL优化问题,claude.ai网页版就够用,直接粘贴SQL和EXPLAIN输出。
如果你要在应用里集成AI数据库优化(比如自动分析慢查询并生成优化建议),可以通过API接入Claude 4.6。国内开发者可以通过 Code80 接入,不需要处理海外支付问题,换个base_url参数即可:
import anthropic
client = anthropic.Anthropic(
api_key="your-code80-api-key",
base_url="https://code.ai80.vip"
)
# 自动分析慢查询
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=2048,
messages=[{
"role": "user",
"content": f"请分析以下慢查询并给出优化建议:nn{slow_query}nnEXPLAIN输出:n{explain_output}"
}]
)
常见问题
Q:Claude给出的索引建议可以直接在生产环境执行吗?
A:不要直接执行。Claude的建议需要你根据实际情况判断:生产环境加索引会锁表,要选低峰期;加索引前要评估索引对写入性能的影响;某些索引在测试数据量下有效,在真实数据分布下可能没用。建议先在测试环境验证效果。
Q:Claude会看到我的数据库密码或敏感数据吗?
A:只要你粘贴的是SQL语句、表结构和EXPLAIN输出(不要粘贴真实的查询结果),就不会涉及敏感数据。表结构和执行计划不包含任何用户数据。
Q:Claude对不同数据库版本的了解准确吗?
A:对主流版本(MySQL 5.7/8.0、PostgreSQL 13-16)的支持比较准确。对于非常新的版本特性(最近半年内发布的),可能不够了解,建议查阅官方文档确认。
Q:统计信息不准导致查询计划不对,怎么处理?
A:把这个问题直接告诉Claude:”EXPLAIN显示查询计划选择了错误的索引,可能是统计信息不准,如何更新统计信息并让查询计划重新生成?”——Claude会给出ANALYZE命令的使用方法和可能的解决方案。









评论前必须登录!
立即登录 注册