Cloud Spannerの実行計画を「制する」:エンジニアが知るべき深淵のチューニング術
Spannerを単なる「SQLが動くRDBMS」だと思っているなら、今すぐその認識を捨ててほしい。Spannerは分散システムそのものであり、その実行計画(Execution Plan)は、システム内部で何千ものノードがどう通信し、どうデータをかき集めているかを映し出す「鏡」だ。
今日は、小手先の最適化ではなく、Spannerの深層を理解し、クエリを極限まで速くするための「読み方」を伝授する。
—
1. 実行計画は「コストの断層」を見抜くためにある
Spannerのクエリ実行計画を眺める際、我々が見るべきは「ノード間の通信」と「データの粒度」だ。Google Cloud Consoleの「クエリ統計情報」や `EXPLAIN ANALYZE` を開いたとき、以下の3つのキーワードに魂を込めて目を光らせてほしい。
Distributed Union:分散の代償
`Distributed Union` は、複数のスプリット(データの断片)に対してクエリを並列実行し、結果をマージする操作だ。
- なぜ重要か: これが大量に発生している場合、クエリが全スプリットを舐めている(フルスキャンに近い)可能性がある。
- チューニングの鍵: WHERE句にプライマリキーやインデックスのプレフィックスが含まれているか? `Distributed Union` の子ノードに `Index Scan` が入っているなら良いが、`Table Scan` があれば、それは設計の敗北を意味する。
Local vs. Remote
実行計画には、ローカルノード内での処理と、ネットワークを跨ぐリモート処理が混在する。
- 暗黙の教訓: `Distributed Union` を跨ぐような複雑なJOINは、ネットワークI/Oを爆発させる。SpannerでJOINを多用するのは、そもそも設計のアンチパターンだ。テーブルの非正規化を恐れるな。
—
2. 実践:クエリチューニングの「鉄の掟」
現場でよくある「遅いクエリ」を、実行計画から読み解く。
ケース:Index Scan が効いていない
「インデックスを貼ったのに遅い」という相談を受けるとき、高確率で発生しているのが「インデックスが選ばれていない」または「Index Scan後のFilterで落ちている」問題だ。
— 実行計画を確認
EXPLAIN ANALYZE
SELECT id, email FROM Users WHERE status = ‘ACTIVE’;
もしここで、`Index Scan` ではなく `Table Scan` が選択されていたら、オプティマイザがインデックスを使うコストを「高すぎる」と判断したということだ。
解決策:
1. Storing Index(付加列)を検討せよ: `SELECT`句に必要なカラムがインデックス自体に含まれていないと、Spannerはインデックスでキーを特定した後、わざわざテーブルの本体を読みに行く(Base Table Lookup)。`STORING` を使ってインデックスにデータを埋め込め。
2. インデックスのプレフィックスを意識せよ: `WHERE status = ‘ACTIVE’ AND created_at > …` のようなクエリなら、`(status, created_at)` の順でインデックスを貼るのが鉄則だ。
—
3. 伝説的エンジニアからの「極限の知見」
私がこれまで多くのプロジェクトで見てきた、Spannerのパフォーマンスを決定づける設計のポイントを共有する。
① 「全権検索」を設計から排除せよ
Spannerにおいて `OFFSET` や `LIMIT` なしの全件検索は「システムへの宣戦布告」だ。実行計画に `Distributed Union` が巨大な負荷として現れたら、それはクエリの問題ではなく、データモデルの設計ミスだ。IDベースのキー設計を徹底し、常にスプリットを絞り込めるクエリを組め。
② JOINを憎め、インターリーブを愛せよ
テーブルの親子関係が明確なら、`INTERLEAVE IN PARENT` を迷わず使え。物理的に同じスプリットにデータが配置されるため、JOINのコストが劇的に下がる。これこそがSpannerの真骨頂であり、一般的なRDBMSとの決定的な違いだ。
③ 実行計画の「Estimated」と「Actual」の乖離を見ろ
`EXPLAIN ANALYZE` を実行すると、推定行数と実際の行数が表示される。ここが大きく乖離している場合、統計情報が古い可能性がある。`ANALYZE` コマンドを叩くタイミングが適切か、あるいはデータ分布が偏っていないか(ホットスポット問題)を疑え。
—
最後に:コードレビューで問いかけるべきこと
チームメンバーのコードをレビューするとき、以下の質問を投げかけてみてほしい。
- 「このクエリの `Distributed Union` は、いくつのスプリットにまたがっているか?」
- 「このJOINを解消するために、インターリーブや非正規化の余地はないか?」
- 「`Index Scan` は、`Storing` によって `Base Table Lookup` を回避できているか?」
Spannerはブラックボックスではない。実行計画という名の地図さえ読めれば、制御不能なパフォーマンス問題など存在しない。
システムを最速で動かすのは、高度なアルゴリズムではない。「データが物理的にどこにあり、どう流れるか」を想像する力だ。 さあ、コンソールを開いて、君のクエリの深淵を覗き込んでみてくれ。
コメント