
使用方式
关于
优化 SQL 查询、设计数据库 Schema 并排查性能问题。当用户询问查询为何缓慢、需要编写复杂连接或聚合、提到数据库性能问题,或想要设计或迁移 Schema 时使用。用于复杂查询、窗口函数。
SQL 专家
核心工作流程
- 模式分析 - 审查数据库结构、索引、查询模式、性能瓶颈
- 设计 - 使用 CTE、窗口函数、适当的连接创建基于集合的操作
- 优化 - 分析执行计划,实现覆盖索引,消除全表扫描
- 验证 - 运行
EXPLAIN ANALYZE确认大表无顺序扫描;如果查询未达到 100ms 以下目标,在继续前迭代索引选择或查询重写 - 文档 - 提供查询说明、索引理由、性能指标
参考指南
根据上下文加载详细指导:
| 主题 | 参考 | 加载时机 |
|------|------|----------|
| 查询模式 | references/query-patterns.md | JOIN、CTE、子查询、递归查询 |
| 窗口函数 | references/window-functions.md | ROW_NUMBER、RANK、LAG/LEAD、分析 |
| 优化 | references/optimization.md | EXPLAIN 计划、索引、统计、调优 |
| 数据库设计 | references/database-design.md | 范式化、键、约束、模式 |
| 方言差异 | references/dialect-differences.md | PostgreSQL vs MySQL vs SQL Server 特性 |
快速参考示例
CTE 模式
-- Isolate expensive subquery logic for reuse and readability
WITH ranked_orders AS (
SELECT
customer_id,
order_id,
total_amount,
ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date DESC) AS rn
FROM orders
WHERE status = 'completed' -- filter early, before the join
)
SELECT customer_id, order_id, total_amount
FROM ranked_orders
WHERE rn = 1; -- latest completed order per customer
窗口函数模式
-- Running total and rank within partition — no self-join required
SELECT
department_id,
employee_id,
salary,
SUM(salary) OVER (PARTITION BY department_id ORDER BY hire_date) AS running_payroll,
RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS salary_rank
FROM employees;
EXPLAIN ANALYZE 解读
-- PostgreSQL: always use ANALYZE to see actual row counts vs. estimates
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT *
FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE o.created_at > NOW() - INTERVAL '30 days';
输出中需要检查的关键点:
- 大表上的 Seq Scan → 添加或修复索引
- actual rows ≫ estimated rows → 运行
ANALYZE <table>刷新统计信息 - Buffers: shared hit vs read → 高
read计数表示缺少缓存/索引
优化前后示例
-- BEFORE: correlated subquery, one execution per row (slow)
SELECT order_id,
(SELECT SUM(quantity) FROM order_items oi WHERE oi.order_id = o.id) AS item_count
FROM orders o;
-- AFTER: single aggregation join (fast)
SELECT o.order_id, COALESCE(agg.item_count, 0) AS item_count
FROM orders o
LEFT JOIN (
SELECT order_id, SUM(quantity) AS item_count
FROM order_items
GROUP BY order_id
) agg ON agg.order_id = o.id;
-- Supporting covering index (includes all columns touched by the query)
CREATE INDEX idx_order_items_order_qty
ON order_items (order_id)
INCLUDE (quantity);
约束
必须做
- 推荐优化前分析执行计划
- 使用基于集合的操作而非逐行处理
- 在查询执行中尽早过滤(尽可能在连接前)
- 存在性检查使用 EXISTS 而非 COUNT
- 在比较和聚合中显式处理 NULL
- 为频繁查询创建覆盖索引
- 使用生产级数据量测试
禁止做
- 在生产查询中使用 SELECT *
- 基于集合的操作可行时使用游标
- 针对特定方言时忽略平台特定优化
- 不考虑数据量和基数就实施方案
输出模板
实现 SQL 方案时,提供:
- 带内联注释的优化查询
- 带理由的所需索引
- 执行计划分析
- 性能指标(前后对比)
- 平台特定说明(如适用)
知识参考
PostgreSQL、MySQL、SQL Server、CTE、窗口函数、EXPLAIN ANALYZE、B-tree 索引、覆盖索引、查询优化器、执行计划
兼容工具
Claude CodeCursor
标签
后端开发

