关于 query-optimize
面向优化 SQL 查询的开发者,提供基于执行计划分析、基准测试和迭代验证的流程,涵盖 SQLite、PostgreSQL 和 MySQL 的常见瓶颈与优化方法。
主要功能
- 01建立性能基线
- 02分析查询执行计划
- 03识别常见查询瓶颈
- 04比较不同优化方案
- 05验证结果与性能
适用场景
- 01排查运行缓慢的数据库查询
- 02对比查询改写的基准性能
- 03验证优化后查询结果
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ letta-ai/ skills --skill query-optimize安装后在 Claude Code 中输入/query-optimize确认已加载。
详细介绍
SQL 查询优化
本技能提供高效优化 SQL 查询的操作指南,重点介绍正确的基准测试、查询计划分析和迭代改进。
核心优化工作流
1. 建立性能基线
进行任何更改之前,先建立明确的性能指标:
- 确定目标:明确“最优”性能是什么样的。查找参考实现、已记录的基准测试或查询复杂度的理论分析。
- 测量原始查询:多次运行并记录执行时间,以考虑缓存的影响。
- 明确目标:将成功定义为“尽可能快”,而不只是“比原来快”。
2. 分析查询计划
优化前后都要分析查询计划:
-- SQLite
EXPLAIN QUERY PLAN <query>;
-- PostgreSQL
EXPLAIN ANALYZE <query>;
-- MySQL
EXPLAIN <query>;
查询计划中需要关注的关键指标:
- 全表扫描(SCAN TABLE)与索引使用(SEARCH TABLE USING INDEX)
- 按行执行的相关子查询
- 为排序/分组创建临时 B-tree
- 中间结果的物化
- JOIN 顺序和 JOIN 类型
3. 找出常见性能问题
相关子查询:引用外层查询列的子查询会对每一行执行一次。尽可能将其转换为 JOIN 或 CTE。
重复计算:多次出现的同一子查询应提取为 CTE 或子查询。
缺少索引:检查 WHERE、JOIN 和 ORDER BY 子句中使用的列是否有索引。
低效聚合:在过滤前对大型结果集执行 GROUP BY。考虑先用 WHERE 过滤。
4. 应用优化技术
考虑多种方案,不要在找到第一个可用方案后就停止:
方案 1:CTE(公用表表达式)
- 预先计算多次使用的值
- 提高可读性
- 注意:某些数据库会物化 CTE,这可能会降低性能
方案 2:窗口函数
- 适用于排名、运行总计和行编号,效率较高
- 存在更简单的替代方案时应避免使用
方案 3:重构子查询
- 将相关子查询转换为 JOIN
- 将谓词下推到子查询中,以缩减中间结果集
方案 4:JOIN 优化
- 重新排列 JOIN,以便尽早过滤
- 使用合适的 JOIN 类型(INNER 与 LEFT)
- 如果可用,考虑使用 JOIN 提示
5. 数据库特定注意事项
SQLite:
- 不支持并行查询执行
- CTE 可能会被物化(这可能会降低性能)
- 与企业级数据库相比,优化器功能有限
- 考虑使用覆盖索引
PostgreSQL:
- 支持并行执行
- 优化器先进,会基于成本进行决策
- 在旧版本(< 12)中,CTE 是优化屏障
MySQL:
- 可以强制或避免物化派生表
- 当优化器选择不佳时,可使用索引提示
验证策略
正确性验证
- 完整结果对比:将所有行和列与原始查询输出进行比较
- 边界情况测试:测试 NULL 值、空结果以及排序/排名中的并列情况
- 抽样验证并不充分:如果完整结果集过大,请使用校验和或行数,并抽样检查部分数据
性能验证
- 多次运行:至少执行 3-5 次,并使用中位数耗时
- 冷缓存与热缓存:如果相关,请测试这两种情况
- 与最优方案比较:如果存在参考方案,应与之比较,而不只是与原始慢查询比较
- 增量分析:分别测量每个 CTE 或子查询,以找出瓶颈
常见陷阱
满足于可用,而非追求优化
- 问题:查询“比以前快”就停止优化,而不是继续追求“尽可能快”
- 预防:开始前务必明确最优性能是什么样的。如有已知的良好实现,请与之比较。
跳过查询计划分析
- 问题:未了解查询变慢的原因就进行更改
- 预防:更改前后始终运行 EXPLAIN。提出解决方案前,先理解查询计划。
过早使用 CTE
- 问题:认为 CTE 总能提升性能。有些数据库会物化 CTE,从而增加开销。
- 预防:同时测试使用和不使用 CTE 的版本。分别分析每个 CTE 的性能。
过度依赖窗口函数
- 问题:在更简单的方法也能奏效时使用 ROW_NUMBER() 或类似函数
- 预防:考虑使用带 MIN/MAX 的 GROUP BY 或简单的相关子查询是否更高效。
测试不充分
- 问题:因超时而只验证部分行
- 预防:使用校验和、行数或哈希比较进行完整验证。先用较小的数据子集测试。
只尝试一种优化方案
- 问题:未探索其他方案就实施一种优化方法
- 预防:选出最佳方案前,至少测试 2-3 种不同方案。
迭代改进流程
- 分析原始查询及其执行计划
- 找出主要瓶颈
- 提出 2-3 种备选方案
- 实施并基准测试每种方案
- 选出性能最佳的方案
- 通过完整结果对比验证正确性
- 记录优化理由
宣布成功前的检查清单
- 已分析并理解查询计划
- 已考虑多种优化方案
- 已将性能与最优方案/参考方案进行比较(而不只是与原始方案比较)
- 已验证完整结果的正确性(而不只是样本)
- 已测试边界情况(NULL、并列值、空结果)
- 已进行多次性能测量
- 已考虑数据库特有的优化
评论
支持 Markdown