关于 ln-651-query-efficiency-auditor
专门审计数据库查询模式的 Worker,会记录问题的严重程度、位置、工作量和建议,面向代码库审计并计算查询效率合规分数,不会自动修复。
主要功能
- 01检测重复读取和重复解析
- 02检查更新、删除及插入循环
- 03识别过量读取和缓存范围问题
- 04记录严重程度与改进建议
- 05计算查询效率评分
适用场景
- 01审查 ORM 代码中的重复数据库读取
- 02查找批量处理数据库操作的机会
- 03在代码库审计中评估查询模式
MCP 相关
本 Worker 优先使用 hex-line MCP 读取本地代码和配置;分析引用链或调用路径有帮助时使用 hex-graph。MCP 不可用或不适用时,会改用内置工具并在报告中注明。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ levnikolaevich/ claude-code-skills --skill ln-651-query-efficiency-auditor安装后在 Claude Code 中输入/ln-651-query-efficiency-auditor确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/audit_output_schema.mdaudit_scoring.mdaudit_summary_contract.mdaudit_worker_core_contract.mdmcp_integration_patterns.mdmcp_tool_preferences.mdtwo_layer_detection.mdreferences/templates/audit_worker_report_template.md详细介绍
**路径:**文件路径(
references/、../ln-*)均相对于此技能目录。
查询效率审计员(L3 Worker)
**类型:**L3 Worker
专门审计数据库查询模式,检查冗余、低效和误用情况。
用途与范围
- 审计查询效率(优先级:高)
- 检查冗余获取、批量操作误用和缓存范围问题
- 将包含严重程度、位置、工作量和建议的结构化发现写入文件
- 计算「查询效率」类别的合规评分(X/10)
输入
**必须读取:**加载 references/audit_worker_core_contract.md 和 references/mcp_tool_preferences.md。
工具策略:你可能作为独立子 Agent 运行,此时宿主的 AGENTS.md 不在适用范围内,因此读取文件、搜索和编辑时默认优先使用 hex-line MCP。仅在 MCP 行为不明确时加载 references/mcp_integration_patterns.md。
接收包含以下内容的 contextStore:tech_stack、best_practices、db_config(数据库类型、ORM 设置)、codebase_root、output_dir。
**领域感知:**支持 domain_mode + current_domain。
当引用链或调用路径有助于查询分析时,优先使用 hex-graph。本地代码/配置读取在可用时优先使用 hex-line。如果 MCP 不可用、不受支持或尚未编入索引,则继续使用内置的 Read/Grep/Glob/Bash,并在报告中说明所用的回退方式。
工作流
检测策略:采用两层检测(候选扫描,然后上下文验证);仅在验证方法不明确时加载 references/two_layer_detection.md。
-
解析 contextStore 中的上下文
- 提取 tech_stack、best_practices、db_config、output_dir
- 按与 ln-624 相同的逻辑确定 scan_path
-
扫描代码库中的违规项
- 所有 Grep/Glob 模式均使用
scan_path - 追踪调用链以查找冗余获取(需要读取调用方和被调用方)
- 所有 Grep/Glob 模式均使用
-
收集发现,包含严重程度、位置、工作量和建议
-
使用惩罚算法计算评分
-
**编写报告:**按照
references/templates/audit_worker_report_template.md在内存中构建完整的 markdown 报告,并通过一次 Write 调用写入{output_dir}/ln-651--global.md -
**返回摘要:**向协调器返回最简摘要(见输出格式)
审计规则(优先级:高)
1. 实体冗余获取
**说明:**同一实体在调用链中从数据库获取两次
检测方法:
- 查找函数 A:它调用
repo.get(id)或session.get(Model, id),然后将id(而非对象)传递给函数 B - 函数 B 也会针对同一实体调用
repo.get(id)或session.get(Model, id) - 常见模式:
acquire_next_pending()返回 job,但_process_job(job_id)又重新获取该 job
检测模式(Python/SQLAlchemy):
- 在服务/处理程序文件中搜索
repo.*get_by_id|session\.get\(|session\.query.*filter.*id - 追踪调用:如果函数接收
entity_id: int/UUID,且内部执行repo.get(entity_id),则检查调用方是否已持有实体对象 - 检查
expire_on_commit设置:若为False,对象在提交后仍然有效
严重程度:
- **高:**API 请求处理程序中存在冗余获取(会增加每个请求的延迟)
- **中:**后台任务中存在冗余获取(影响较小)
- **降低等级的情况:**初始化/迁移代码中的获取(只运行一次)→ 低。仅管理员可访问且流量较低的端点 → 降低一个等级
**建议:**传递实体对象而不是 ID,或者在 expire_on_commit=False 时移除第二次获取
**工作量:**S(将签名改为接收对象而不是 ID)
2. N-UPDATE/DELETE 循环
内容: 循环执行单条 UPDATE/DELETE 操作,而不是使用单个批量查询
检测:
- 模式:
for item in items: await repo.update(item.id, ...)或for item in items: await repo.delete(item.id) - 模式:
for item in items: session.execute(update(Model).where(...))
检测模式:
- 搜索
for .* in .*:,并检查其后 1-3 行内是否出现repo\.(update|delete|reset|save|mark_) - 搜索
for .* in .*:,并检查其后 1-3 行内是否出现session\.execute\(.*update\(
严重程度:
- HIGH: 循环处理超过 10 个项目(与数据库进行 N 次单独往返)
- MEDIUM: 循环处理不超过 10 个项目
- 降低严重程度的情况: 引导/迁移代码中的循环(只运行一次)→ LOW。仅限管理员使用的端点 → 降低一个级别
建议: 替换为单条 UPDATE ... WHERE id IN (...) 或 session.execute(update(Model).where(Model.id.in_(ids)))
工作量: M(重写查询并测试)
3. 不必要的解析
内容: 当调用方作用域中已经有某个值时,仍从数据库重新解析该值
检测:
- 方法接收
profile_id并据此解析 engine,但调用方已经确定了engine - 方法接收
lang_code并查询 dialect_id,但调用方已经有lang和dialect - 模式:函数接收
X_id,执行get(X_id)并提取.field,但调用方已经有field
严重程度:
- MEDIUM: 每次调用都会增加一次数据库查询,尤其是在高频路径中
建议: 将方法拆分为两个变体:with_known_value(value, ...) 和 resolving_value(id, ...);或者直接传入已解析的值
工作量: S-M(重构签名并更新调用方)
4. 过度获取
内容: 只需要少量字段时,却加载完整的 ORM 模型
检测:
- 对于列数超过 10 列的模型,使用
session.query(Model)或select(Model),但没有.options(load_only(...)) - 尤其是在返回大量行的列表/搜索端点中
- 模式:加载完整实体,但只使用其中 2-3 个字段
严重程度:
- MEDIUM: 列数超过 15 列的大型模型用于列表端点
- LOW: 列数少于 10 列的小型模型,或单实体端点
建议: 对列表查询使用 load_only()、defer() 或原始查询 select(Model.col1, Model.col2)
工作量: S(在查询中添加 load_only)
5. 缺少批量操作
内容: 顺序执行 INSERT/DELETE/UPDATE,而不是使用批量操作
检测:
- 使用
for item in items: session.add(item),而不是session.add_all(items) - 使用
for item in items: session.delete(item),而不是批量删除 - 模式:循环中每次迭代都执行单条
INSERT
严重程度:
- MEDIUM: 循环中任何顺序执行的 add/delete(错过批量优化机会)
建议: 使用 session.add_all()、session.execute(insert(Model).values(list_of_dicts))、bulk_save_objects()
工作量: S(将循环替换为批量调用)
6. 缓存作用域错误
内容: 对于很少变化的数据使用请求级缓存(应该使用应用级缓存)
检测:
- 服务注册为请求级(例如,通过 FastAPI
Depends()),且内部有缓存(_cache字典、_loaded标志) - 每次请求都会通过开销较大的查询(JOIN、聚合)填充缓存
- 数据 TTL 远大于请求时长(例如,engine 配置、语言列表、功能标志)
检测模式:
- 查找包含
_cache、_loaded、_initialized属性的类 - 检查类是否按请求创建(通过 DI 注册作用域)
- 比较:数据变化频率与缓存生命周期
严重程度:
- HIGH: 开销较大的查询(JOIN、子查询)仅按请求缓存
- MEDIUM: 简单查询按请求缓存
建议: 将缓存移至应用级服务(单例),添加基于 TTL 的失效机制,或使用可配置 TTL 的 CacheService
工作量: M(更改 DI 作用域并添加 TTL 逻辑)
评分算法
必须阅读: 加载 references/audit_scoring.md。
输出格式
必须阅读: 加载 references/templates/audit_worker_report_template.md。
按照 references/audit_summary_contract.md 编写 JSON 摘要。在托管模式下,调用方会传入 runId 和 summaryArtifactPath;在独立模式下,工作程序会按照共享契约生成自己的运行级制品路径。
将报告写入 {output_dir}/ln-651--global.md,并设置 category: "Query Efficiency",检查项包括:redundant_fetch、n_update_delete_loop、unnecessary_resolve、over_fetching、missing_bulk_ops、wrong_caching_scope。
按照 references/audit_summary_contract.md 返回摘要。
当 summaryArtifactPath 缺失时,将独立运行时摘要写入 .hex-skills/runtime-artifacts/runs/{run_id}/evaluation-worker/{worker}--{identifier}.json,并可选择在结构化输出中回显相同的摘要。
Report written: .hex-skills/runtime-artifacts/runs/{run_id}/audit-report/ln-651--global.md
Score: X.X/10 | Issues: N (C:N H:N M:N L:N)
关键规则
遵循已加载的 references/audit_worker_core_contract.md。
- 不要自动修复: 仅报告
- 追踪调用链: 规则 1 和规则 3 要求同时读取调用方和被调用方
- 感知 ORM: 标记冗余提取前,检查
expire_on_commit、autoflush和会话作用域 - 结合上下文: 数据集较小或操作不频繁时,较简单的代码可能更合适
- 排除测试: 不要标记测试固件或设置代码
完成定义
遵循已加载的 references/audit_worker_core_contract.md。
- 成功解析 contextStore(包括 output_dir)
- 确定 scan_path(领域路径或代码库根目录)
- 完成全部 6 项检查:
- 冗余提取、N-UPDATE 循环、不必要的解析、过度提取、批量操作、缓存作用域
- 收集问题,并注明严重性、位置、工作量和建议
- 使用惩罚算法计算分数
- 将报告写入
{output_dir}/ln-651--global.md(通过单次原子 Write 调用) - 按照契约写入摘要
参考文件
- 审计输出架构:
references/audit_output_schema.md
版本: 1.0.0 最后更新: 2026-02-04