最適化は速度の問題ではない。コストの問題だ

クラウドDWHには、オンプレミス時代と決定的に異なる性質がある。 すべてのクエリに値札がついている という事実だ。

Snowflakeのコンピュートコストは、クエリが消費するウェアハウスの稼働時間で決まる。つまり、不要なデータを読めば読むほど、課金額が上がる。「動けばいい」で書いたSQLが、月末の請求書に直結する。

この構造を理解すると、Snowflakeが地味に進化させている機能群の意味が見えてくる。SEARCH関数、HyperLogLog、LIMIT Pruning。どれもプレスリリースの見出しにはならないが、 実務の請求額を変える機能 だ。

よくある失敗:コストを意識しないクエリ

現場でよく見る3つのパターンがある。

1. 数十億行に対する COUNT(DISTINCT)

-- 全データを読む。正確だが、コストも正確に高い
SELECT COUNT(DISTINCT user_id) FROM events;

ユニークユーザー数を出すだけで、数十億行のフルスキャンが走る。ダッシュボードの更新が毎時回っていれば、月間のコストは無視できない金額になる。

2. LIKE ‘%keyword%’ の安易な使用

-- インデックスが効かない。全行スキャン確定
SELECT * FROM logs WHERE message LIKE '%timeout%';

先頭ワイルドカードを使った瞬間、Snowflakeのプルーニングは無力化される。数百GBのログテーブルを毎回フルスキャンする羽目になる。

3. クエリプロファイルを見ない

「結果が返ってくるから問題ない」。この判断が最も高くつく。Snowflakeのクエリプロファイルには、スキャンしたバイト数、パーティションのプルーニング率、スピルの有無が記録されている。 見ないということは、請求書を見ないのと同じ だ。

コスト視点で見るSnowflakeの3機能

クエリ方式別のコストインパクト比較

SEARCH関数:LIKEを置き換えるコスト削減策

SEARCH関数は、テキスト検索を オプティマイザが最適化できる形 に変換する。

-- コストが高い:プルーニング無効
SELECT * FROM inquiries
WHERE content LIKE '%キャンセル%' OR content LIKE '%返品%';

-- コストが低い:オプティマイザが最適化
SELECT * FROM inquiries
WHERE SEARCH(content, 'キャンセル OR 返品');

構文の違いは小さい。しかしLIKEの先頭ワイルドカードがプルーニングを無効にするのに対し、SEARCH関数はSnowflakeの内部インデックスを活用できる。問い合わせログの分析、自由記述欄の分類、大量テキストの検索。これらのユースケースで スキャン量が桁違いに変わる

HyperLogLog:98%の精度で十分なら、コストは1/1000

「このデータセットに何種類のユーザーがいるか」。この質問に正確に答えるには、全行を読む必要がある。だが、多くのビジネス判断において「100万人」と「99万8千人」の差は意味を持たない。

-- 正確だが高コスト:全行スキャン
SELECT COUNT(DISTINCT user_id) FROM events;

-- 98%精度で1/1000のコスト
SELECT APPROX_COUNT_DISTINCT(user_id) FROM events;

HyperLogLogは、ハッシュ値の統計的性質を利用してユニーク数を推定するアルゴリズムだ1約1.5KBのメモリ で数億件のユニークカウントを実現する。Redis、Elasticsearch、ClickHouseでも採用されている、実績ある技術だ。

ポイントは「精度を落とす」のではなく、 「必要十分な精度を選ぶ」 という判断にある。毎時更新のダッシュボードに小数点以下の正確さは要らない。

LIMIT Pruning:読まないデータには課金されない

Snowflakeはデータをマイクロパーティション単位で管理している。LIMIT句がある場合、必要なパーティションだけを読んで結果を返す仕組みがある2

-- プルーニングが効けば、数パーティションで完了
SELECT * FROM large_table
ORDER BY created_at DESC
LIMIT 100;

プルーニングが効くと スキャン量が劇的に減り、課金も比例して下がる 。Apache DataFusionでも同様の最適化が実装されており、「読むデータ量を最小化する」方向はデータ基盤全体のトレンドだ。

80/20ルール:コストの源泉を特定する

DWHのコスト最適化で最も効果が高いのは、新機能の導入ではない。 コストの80%を生んでいる20%のクエリを特定すること だ。

Snowflakeのクエリ履歴には、各クエリのスキャンバイト数、実行時間、ウェアハウスの消費クレジットが記録されている。これを週次でレビューするだけで、最適化すべきクエリが見える。

-- コスト上位のクエリを特定する
SELECT query_id, query_text,
       bytes_scanned,
       total_elapsed_time,
       partitions_scanned,
       partitions_total
FROM snowflake.account_usage.query_history
WHERE start_time > DATEADD(day, -7, CURRENT_TIMESTAMP())
ORDER BY bytes_scanned DESC
LIMIT 20;

この20件を改善するだけで、月間コストが数十パーセント下がることは珍しくない。最新のAI機能を検討する前に、まずこのクエリを実行すべきだ。

見えない最適化がROIを決める

クラウドDWHの本当のROIは、導入時の機能比較表では測れない。日々のクエリが生むコストと、それを抑制する地味な最適化の積み重ねで決まる。

SEARCH関数でLIKEを置き換える。APPROX_COUNT_DISTINCTで十分な場面を見極める。クエリプロファイルを定期的に確認する。どれも派手さはないが、 請求書に反映される改善 だ。

データ基盤の価値は、導入した瞬間ではなく、運用の中で可視化される。その可視化を支えるのは、プレスリリースに載る機能ではなく、こうした地味な最適化技術だ。

Footnotes

  1. Philippe Flajolet, Éric Fusy, Olivier Gandouet, Frédéric Meunier. “HyperLogLog: the analysis of a near-optimal cardinality estimation algorithm”. DMTCS Proceedings, 2007.

  2. Snowflake Documentation. “Understanding & Using Query Profile”. Pruning and partition elimination.