mcpField
Q
query-optimize

query-optimize

github.com/letta-ai数据与数据库15235 次安装4 周前更新
代码仓库

关于 query-optimize

面向优化 SQL 查询的开发者,提供基于执行计划分析、基准测试和迭代验证的流程,涵盖 SQLite、PostgreSQL 和 MySQL 的常见瓶颈与优化方法。

主要功能

  1. 01建立性能基线
  2. 02分析查询执行计划
  3. 03识别常见查询瓶颈
  4. 04比较不同优化方案
  5. 05验证结果与性能

适用场景

  1. 01排查运行缓慢的数据库查询
  2. 02对比查询改写的基准性能
  3. 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:

  • 可以强制或避免物化派生表
  • 当优化器选择不佳时,可使用索引提示

验证策略

正确性验证
  1. 完整结果对比:将所有行和列与原始查询输出进行比较
  2. 边界情况测试:测试 NULL 值、空结果以及排序/排名中的并列情况
  3. 抽样验证并不充分:如果完整结果集过大,请使用校验和或行数,并抽样检查部分数据
性能验证
  1. 多次运行:至少执行 3-5 次,并使用中位数耗时
  2. 冷缓存与热缓存:如果相关,请测试这两种情况
  3. 与最优方案比较:如果存在参考方案,应与之比较,而不只是与原始慢查询比较
  4. 增量分析:分别测量每个 CTE 或子查询,以找出瓶颈

常见陷阱

满足于可用,而非追求优化
  • 问题:查询“比以前快”就停止优化,而不是继续追求“尽可能快”
  • 预防:开始前务必明确最优性能是什么样的。如有已知的良好实现,请与之比较。
跳过查询计划分析
  • 问题:未了解查询变慢的原因就进行更改
  • 预防:更改前后始终运行 EXPLAIN。提出解决方案前,先理解查询计划。
过早使用 CTE
  • 问题:认为 CTE 总能提升性能。有些数据库会物化 CTE,从而增加开销。
  • 预防:同时测试使用和不使用 CTE 的版本。分别分析每个 CTE 的性能。
过度依赖窗口函数
  • 问题:在更简单的方法也能奏效时使用 ROW_NUMBER() 或类似函数
  • 预防:考虑使用带 MIN/MAX 的 GROUP BY 或简单的相关子查询是否更高效。
测试不充分
  • 问题:因超时而只验证部分行
  • 预防:使用校验和、行数或哈希比较进行完整验证。先用较小的数据子集测试。
只尝试一种优化方案
  • 问题:未探索其他方案就实施一种优化方法
  • 预防:选出最佳方案前,至少测试 2-3 种不同方案。

迭代改进流程

  1. 分析原始查询及其执行计划
  2. 找出主要瓶颈
  3. 提出 2-3 种备选方案
  4. 实施并基准测试每种方案
  5. 选出性能最佳的方案
  6. 通过完整结果对比验证正确性
  7. 记录优化理由

宣布成功前的检查清单

  • 已分析并理解查询计划
  • 已考虑多种优化方案
  • 已将性能与最优方案/参考方案进行比较(而不只是与原始方案比较)
  • 已验证完整结果的正确性(而不只是样本)
  • 已测试边界情况(NULL、并列值、空结果)
  • 已进行多次性能测量
  • 已考虑数据库特有的优化

评论

支持 Markdown