pre-project setup checklist の一項目。「遅くなってから測る手段を作る」のでは遅いため、繋ぎ込みの実装が始まる前に検証手段を用意しておく。エージェントに実装させる場合はとくに、これがないと「動くが遅い」実装が緑のまま通過する。
ANALYZE(統計情報の収集)を実行する手順が組み込まれているこれがない状態で性能検証を組んでも、すべてノイズになる。 開発用DBの1000行では全件走査が最速なので、正しい判断が「遅い」と判定される。最初に投資すべきはここ。
「300ms以内」は仕様でも設計でもなく要求の成功基準。エージェントに決めさせると最初の実測値が基準になり、劣化を検出できなくなる。ここは自動化できない。
npm run db:check)指示書に「実行計画を確認せよ」と書くだけでは、エージェントが解釈で基準をずらせる。コマンド化すれば基準の改変が差分に出る。
判定は必ず以下の順序で、上位が失敗したら下位を評価しない。
| 優先 | 判定 | 内容 | 失敗条件にするか |
|---|---|---|---|
| 1 | 機能テスト | 仕様どおり動くこと | 必須 |
| 2 | クエリ発行回数 | N+1検出。件数非依存で最も安定 | する |
| 3 | 効率比 | 返した行数に対し読んだ行数/バッファが異常でないか | する |
| 4 | 実行時間(ms) | 参考値 | しない(ログ出力のみ) |
msを失敗条件にすると誤魔化される。 テストデータを減らす、
LIMITを足す(仕様が変わる)、索引を乱造する(書き込み劣化はこの閾値では見えない)、キャッシュで2回目だけ速くする——どれもmsは改善する。回数と比率は比なので誤魔化せない。
"Index Scan" in output 等)をアサートしていない計画の形は実装詳細。DBバージョン・統計・データ件数・コストパラメータで変わる。件数が少なければ全件走査を選ぶのが正しいので、このテストは「プランナが正しく判断したとき赤くなる」。宣言的インターフェースのテストで実装詳細を固定している状態。
代わりに安定するもの:
「索引を足せば直る」ケースと「データモデルが間違っている」ケースを、実行計画から区別することはできない。後者を自動修正させると、根本原因の上に索引が積み上がる。
Red-Green-Refactorの内側は「速く・決定的に」が生命線。性能は環境依存で遅いので、内側に置くと開発が止まる。
| 広く見つける(定点観測) | 一点を深く見る(虫眼鏡) | |
|---|---|---|
| PostgreSQL | pg_stat_statements / auto_explain | EXPLAIN (ANALYZE, BUFFERS) |
| MongoDB | Database Profiler | explain("executionStats") |
| Elasticsearch | slow log | ?profile=true |
auto_explain.log_min_duration を設定。log_analyze = on は全クエリに計測コストが乗るため、まずoffで始めて段階的にEXPLAIN ANALYZE は実際に実行する。 UPDATE/DELETE に対しては BEGIN; ... ROLLBACK; で囲むESをデータストアに使う場合、上記の枠組みがそのままは適用できない。
took を単発で判定条件にしていないフィルタキャッシュ・リクエストキャッシュにより2回目から速くなる。ウォームアップして複数回実行し中央値を取らないと安定しない。RDBMSより「msが揺れる/誤魔化される」度合いが強い。
rewrite_time の異常を監視している(ワイルドカードや巨大な terms の展開爆発を検出できる)補足として、Query DSL側にはコストベースのプランナが存在しない(転置インデックスという単一経路のため選択が発生しない)。「効率比」に相当する指標がprofile出力から素直に取れないので、構造的な指標(書き換え時間・リクエスト回数・対象shard数)に寄せる。
なお _explain APIは1ドキュメントのスコア内訳を出すもので、性能診断用ではない。名前が紛らわしい。