关于 backend-perf
用于审查后端代码性能模式的技能,会逐项说明检查结果及适用性。面向开发者,区分通用检查与 PostgreSQL 专项检查。
主要功能
- 01并行执行独立异步调用
- 02检测顺序式 N+1 查询
- 03检查分页计数查询
- 04审查 PostgreSQL 索引覆盖
- 05检查稳定函数的复用
- 06检查竞态处理
适用场景
- 01合并前审查后端改动
- 02审计 PostgreSQL 查询计划和索引
- 03查找重复读取和过量字段查询
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ bhagyamudgal/ skills --skill backend-perf安装后在 Claude Code 中输入/backend-perf确认已加载。
详细介绍
后端性能检查清单
我会根据手头的代码逐项检查以下内容,并逐项给出结论:已落实、无问题或不适用,并说明原因。未提及的检查,即表示我没有执行。
标记为 [pg] 的检查仅适用于 PostgreSQL。在其他存储上,我会跳过这些检查,而不是将其转换为其他存储的检查。
- 并行异步调用。相互独立的异步调用应通过
Promise.all并行执行,绝不能逐个等待。 - N+1 查询。不得在顺序执行的
for或for await循环中查询。应改用IN子句批量查询或使用联接。对少量有利于索引的查询,使用Promise.all(items.map(q => oneQuery(q)))并行执行,不属于顺序 N+1。限制扇出量:对于无上限的items列表,应明确设置上限或并发限制,因为 N 个并行查询仍会打开 N 个连接。除非EXPLAIN显示批量联接速度更快,否则应保留并行执行的结构,因为批量查询往往会失去逐行使用索引的优势。 - 分页计数。计数和数据行应来自同一个查询:使用
count(*) OVER ()窗口函数或单个 CTE,而不是在数据查询旁单独执行COUNT(*)。 - 索引覆盖
[pg]。每个生产环境中的WHERE子句都需要匹配的索引。similarity(col, ...)、@@ to_tsvector(...)或LIKE '%pattern%'需要在同一个 PR 中添加对应的gin (col gin_trgm_ops)或gin (to_tsvector('lang', col))索引,或者添加一行注释引用接受顺序扫描的 ADR 或 issue。优先使用可利用索引的%运算符,而不是直接比较similarity() > threshold,但必须使用匹配的阈值:%会根据会话的pg_trgm.similarity_threshold(默认值为 0.3)进行判断,因此应将其设为查询使用的阈值,并确认结果集等价,同时通过 EXPLAIN 确认规划器选择了该索引。 - STABLE 函数复用
[pg]。pg_trgm.similarity和ts_rank是 STABLE 而非 IMMUTABLE,因此 PostgreSQL 不会可靠地记忆同一条 SELECT 中重复的函数调用。需要使用两次的值,例如既用于投影又用于GREATEST(...)的值,应在WITH ... AS MATERIALIZEDCTE 中计算一次。普通子查询别名无法保证这一点。规划器可能会将其展开,并针对每一行分别计算。 - 只选择所需列。列表接口应明确列出需要的列,而不是选择整行。
- 复用已获取的行。用于所有权检查而获取的行,应由处理程序直接返回。不要再按 id 获取一次。
- 重写前先执行 EXPLAIN
[pg]。任何查询结构调整、批处理、联接、索引操作,或将 N 个并行查询替换为 1 个批量查询,都应提供代表性数据上当前结构与拟议结构的EXPLAIN (ANALYZE, BUFFERS)数值。保留速度更快的结构。在差异对比中看似更快的重写,在真实数据上可能慢 10 到 100 倍。 - 竞态条件。当 2 个或更多写入方可能操作同一行时,应使用事务。异步操作的完成顺序并不等于代码中的顺序。应通过
await或Promise.all明确指定顺序,而不是依赖偶然的串行执行。必须保持原子性的检查与写入,应在[pg]上使用SELECT ... FOR UPDATE,或使用唯一约束,而不是应用层锁定。
评论
支持 Markdown