NGW開発BLOG
← 記事一覧へ
·#012

本番相当のデータで性能を測る見積りが信頼できる検証環境

少量のテストデータでは性能問題は再現しない。本番と同規模・同分布のデータを手元に置くと、EXPLAINの見積りが実運用の見積りとして信頼できる理由を綴る。

一瞬で終わるクエリは、何も教えてくれない

開発中に書いたSQLを手元で叩くと、まばたきする間に結果が返ってくる。「速い、問題ない」と判断してリリースする。そして本番で、同じクエリが数秒かかると報告が来る。

この落差の正体は、クエリの善し悪しではない。手元にあるデータの量と形だ。

開発環境のテーブルに数十行しか入っていなければ、全表スキャンだろうがfilesortだろうが一瞬で終わる。オプティマイザにとって、数十行を舐めるのと索引を引くのはコスト差がほぼない。だから「問題のあるクエリ」と「問題のないクエリ」が、手元では見分けられない。性能問題は、行数が本番規模に達して初めて表面化する種類のバグなのだ。

そこで我々は、開発環境に「実際に使われているものと同じ規模・分布のデータ」を置いている。具体的には、最もデータ量の多い団体の本番相当データを一式、手元に構えている。これが検証の土台になる。

なぜ「規模」だけでなく「分布」なのか

行数を合わせるだけなら、ループで合成データを生成すれば済む話に思える。だが、それでは足りない。オプティマイザの判断を左右するのは行数そのものではなく、データの分布 — カーディナリティ、欠損の割合、値の偏り — だからだ。

例えば、ある業務テーブルの「ステータス」列を考える。合成データで全ステータスを均等に生成すれば、どの値もほぼ同じ割合で存在する。しかし実データでは「完了」が9割を占め、「差戻し」は0.1%しかない、といった強い偏りがあるのが普通だ。

この偏りは索引の効き方を根本から変える。

-- 実データでは「差戻し」は極端に少ない → 索引が劇的に効く
SELECT * FROM applications WHERE status = '差戻し';

-- 「完了」は9割を占める → 索引を引くより全表スキャンが速い、と
-- オプティマイザが判断することさえある
SELECT * FROM applications WHERE status = '完了';

同じ列の同じ索引でも、渡す値によってオプティマイザは索引利用と全表スキャンを使い分ける。その分岐点は、実データの分布を見て初めて正しく再現される。均等な合成データの上でEXPLAINを眺めても、本番のオプティマイザとは違う結論が出る。測っているつもりで、別物を測っていることになる。

EXPLAINのrowsを、見積りとして信じられるか

本番相当のデータが手元にあることの本当の価値は、EXPLAIN の出力がそのまま実運用の見積りとして使える点にある。

EXPLAIN
SELECT w.*
FROM workflow w
WHERE w.staff_cd = ? AND w.apply_date BETWEEN ? AND ?;

このとき見るのは主に三つ。type が全表スキャン(ALL)か索引参照(ref/range)か。rows が数十万なのか数百なのか。ExtraUsing filesortUsing temporary が出ていないか。

手元のデータが本番と同規模・同分布であれば、ここに出てくる rows の見積りは、そのまま本番でスキャンされる行数の見積りになる。「この結合は数十万行を舐める」「この索引を足せば rows が三桁まで落ちる」といった判断が、机上の空論ではなく実測に裏付けられる。索引を一本追加してみて、EXPLAINANALYZE で前後を比べ、効果を確かめる — その一連の検証が、本番に触れることなく手元で完結する。

実際、決裁状況の一覧が重いという問題に索引で対処したときも、判断の根拠はすべて手元の大規模データ上のEXPLAINだった。少量データなら、そもそも重さが再現せず、索引の要否を議論する土俵にすら立てなかっただろう。

AIとの協働作業での学び

性能検証の再現性は、コードではなく環境のデータ量で決まる。

  • 少量データでは全表スキャンもfilesortも一瞬で終わり、問題が原理的に見えない。
  • 合成データは規模を揃えても分布が違い、オプティマイザが本番と違う判断を下す。
  • 本番と同規模・同分布のデータを手元に置いて初めて、EXPLAINのrowsや実行時間が「見積り」として信頼できる。

推測するな、計測せよ — この格言には、静かな前提が隠れている。何を計測しているのか、だ。本物に近いデータの上で測らなければ、その計測値は本番について何も語っていない。性能を測るなら、まず測る対象を本番に寄せることから始めたい。