mcpField
S
sql-schema-audit

sql-schema-audit

github.com/mizchi数据与数据库41660 次安装1 周前更新
代码仓库

关于 sql-schema-audit

sql-schema-audit 面向 DBA 的重复性审查任务,检查 SQLite 索引覆盖情况和潜在 N+1 查询。脚本会分析查询计划中的扫描、列出待核查的索引,并标记循环供人工复审。

主要功能

  1. 01归因查询计划中的 SCAN 步骤
  2. 02列出可能未使用的索引
  3. 03识别用于外键级联的索引
  4. 04标记调用 sqlc 函数的循环
  5. 05支持可配置的扫描模式

适用场景

  1. 01架构变更后检查索引
  2. 02发布前核查待处理的索引
  3. 03检查数据库循环中的潜在 N+1 查询

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mizchi/skills --skill sql-schema-audit

安装后在 Claude Code 中输入/sql-schema-audit确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

README.md
scripts/
index-coverage.mjs
n-plus-one.mjs

详细介绍

SQL Schema Audit

将其用于两项周期性的 DBA 审查任务:

  1. 哪些地方缺少索引? 遍历每个查询计划,并将每个 SCAN <table> 归类为已知的有意情况(无法创建覆盖索引)或缺口(表完全没有索引)。
  2. 哪些地方可能存在代码 N+1 问题? 查找调用 sqlc 生成函数的 for 循环——这是审查辅助工具,不会直接判定失败,因为批量插入是合理的。

index-coverage.mjs

# `scripts/` is relative to THIS skill's directory; from elsewhere use the
# absolute path. `--out` is OPTIONAL — omit it and the report prints to stdout.
# The printed report IS the deliverable; the file is just a persisted copy.
node scripts/index-coverage.mjs \
  --schema your-project/db/schema.sql \
  --queries your-project/db/queries.sql \
  [--out your-project/.linters/index-coverage.txt]

输出章节:

  • 逐查询 SCAN 归因:列出每个产生 SCAN 步骤的查询,并说明 SCAN 的原因。FIX 标记表示表完全没有索引(需要立即处理)。没有标记表示表有索引,但规划器仍选择了扫描——通常没问题(表较小、WHERE 形状不常见)。
  • 可考虑删除的索引:没有任何目录查询通过 SEARCH USING INDEX 引用、且不覆盖任何 FK CASCADE 来源列的索引。
  • 承担 FK 级联作用的索引:未被 SELECT 使用、但前导列与外键的 from 列表匹配的索引。SQLite 不会自动为 FK 列创建索引;如果没有显式索引,ON DELETE CASCADE 就会通过全表扫描遍历子表。这些索引看起来“未使用”,但对删除性能至关重要。

FK 感知步骤很重要:在包含许多 owner_user_id 外键的典型架构中,大多数“未使用”的索引实际上都在服务于级联删除。删除它们会悄悄导致删除性能下降。

删除候选索引时

删除前请交叉核查:

  1. 此审计只检查由 sqlc 管理的查询。内联 SQL(FTS5 MATCH、动态 LIKE、向量查询)不会纳入审计。删除前,请在代码库中搜索索引名称或其列组合。
  2. 对于静态 EXPLAIN 无法复现的查询形状,规划器可能会动态选择该索引(例如,不同的绑定值分布会改变所选索引)。删除候选的含义是“在已分析的目录中没有 SELECT 选择它”——这是必要条件,但不是充分条件。
  3. 逻辑上“被”超集索引覆盖的索引通常可以删除——规划器会改用更长的索引。删除后,请使用 sql-plan-audit 验证,确保没有查询退化为 SCAN。

n-plus-one.mjs

node scripts/n-plus-one.mjs your-project/src

基于正则表达式扫描 12 行范围内调用 sqlc 生成函数的 for 循环。可调整参数:

  • --callee-prefix @db.,db.:匹配其他绑定风格(Rust 的 state.db.、Go 的 q. 等)。
  • --window 20:扩大向前查找范围。

该脚本始终返回 0——N+1 候选需要人工审查。请将其用作审查辅助工具,而不是 CI 门禁。

在类型完善的代码库中,大多数候选都是合理的批量插入(在 for file in files 中调用 create_skill_file,在 for tag in tags 中调用 add_skill_tag)。本报告旨在捕捉的,正是那种在循环中执行 SELECT 的真实问题。

何时调用

  • 架构变更后(添加或删除索引)。
  • 发布前:一次性检查“哪些索引未使用?”。
  • 功能新增了访问数据库的 for 循环时——查看 N+1 报告。

不在范围内

  • 代码与生产环境之间的架构漂移:需要读取线上数据库架构,并与 schema.sql 进行比较。不在此范围内。
  • CHECK / NOT NULL 审计:使用 schemalint 或类似工具。或许值得后续开发一个技能。
  • EXPLAIN ANALYZE / 实际行数:SQLite 无法静态提供这些信息。

引擎扩展性

基于 PRAGMA 的自省(PRAGMA index_list、PRAGMA index_info、PRAGMA foreign_key_list)仅适用于 SQLite。对于 Postgres:查询 pg_indexes + pg_stat_user_indexes(可提供实际使用次数,比基于 EXPLAIN 的启发式方法准确得多)+ information_schema.referential_constraints。对于 MySQL:查询 information_schema.STATISTICS + information_schema.KEY_COLUMN_USAGE。

N+1 检测器与数据库引擎无关,但 --callee-prefix 启发式规则取决于代码生成约定(sqlc / sqlx / typeorm / prisma)。

要求

  • Node 22 或更高版本(使用内置的 node:sqlite 模块)。
  • sqlc 风格的查询目录或兼容格式。

文件

  • scripts/index-coverage.mjs — 按查询归因 SCAN + 删除候选项 + FK 级联关键项列表。
  • scripts/n-plus-one.mjs — for 循环 sqlc 调用检测器。

评论

支持 Markdown