mcpField
S
sql-schema-audit

sql-schema-audit

github.com/mizchiデータ・データベース41660 回インストール1 週間前に更新
リポジトリ

sql-schema-audit について

sql-schema-auditは、SQLiteのインデックス網羅性とN+1クエリの可能性を定期的に調べるDBA向けスキルです。クエリ計画のスキャンを分析し、確認が必要なインデックス候補やループを人手レビュー用に示します。

主な機能

  1. 01クエリ計画のSCANを分類
  2. 02未使用の可能性があるインデックスを列挙
  3. 03外部キーのカスケードに使うインデックスを識別
  4. 04sqlc関数を呼ぶループを検出
  5. 05スキャン条件の調整

活用シーン

  1. 01スキーマ変更後のインデックス確認
  2. 02リリース前のインデックス候補の点検
  3. 03DBループ内の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 スキーマ監査

DBA が繰り返し行う次の 2 つのレビュー作業に使用します。

  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、ベクトル検索など)は監査対象外です。削除する前に、インデックス名またはカラムの組み合わせをコードベース内で grep してください。
  2. 静的な EXPLAIN では再現されないクエリの形では、プランナーが実行時に動的にそのインデックスを選択することがあります(たとえば、バインド値の分布が変わり、選択されるインデックスが変化する場合)。削除候補とは「分析対象のカタログでは、SELECT が一度も選択しない」という意味です。これは必要条件であり、十分条件ではありません。
  3. 論理的に上位集合のインデックスと「重複」するインデックスは、通常削除できます。プランナーは、より長いインデックスを使うよう切り替えます。削除後に sql-plan-audit で検証し、クエリが SCAN に戻っていないことを確認してください。

n-plus-one.mjs

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

for ループ内の 12 行以内で sqlc が生成した関数を呼び出している箇所を、正規表現でスキャンします。次のオプションで調整できます。

  • 他のバインディング形式(Rust の state.db.、Go の q. など)に一致させるには、--callee-prefix @db.,db. を指定します。
  • 先読み範囲を広げるには、--window 20 を指定します。

このスクリプトは常に 0 を返します。N+1 の候補には人によるレビューが必要です。CI のゲートではなく、レビューの補助として使用してください。

型付けがしっかりしたコードベースで見つかる候補の大半は、正当なバッチ挿入です(for file in files 内の create_skill_file、for tag in tags 内の add_skill_tag など)。このレポートで検出したいのは、実際に問題となる SELECT のループ内実行です。

実行するタイミング

  • スキーマを変更した後(インデックスの追加または削除)。
  • リリース前に、「未使用のものは何か」を一度確認するとき。
  • DB にアクセスする for ループを含む機能を追加したとき。N+1 レポートを目視確認してください。

対象外

  • コードと本番環境のスキーマの不一致:稼働中の DB スキーマを読み取り、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 呼び出し検出器。

コメント