Snowflake SEARCH OPTIMIZATION入門|ID検索・ポイントルックアップを高速化する方法

Snowflake SEARCH OPTIMIZATION入門|ID検索・ポイントルックアップを高速化する方法 Snowflake

はじめに:大量データから1行を素早く取り出したい!

こんにちは!Snowflakeを使っていると、「数億行あるテーブルから特定の1行をピンポイントで取り出したい」というシーンに出会いませんか?例えば顧客IDで会員情報を引いたり、注文番号で履歴を検索したり…。こうした「同じテーブルに対して、選択的な検索を何度も繰り返す」使い方のテーブルを、本記事では便宜的に「反復検索されるテーブル」と呼ぶことにします。

※「反復検索されるテーブル」は本記事独自の便宜的な呼び方であり、Snowflakeの正式なテーブル種別ではありません。永続テーブル・一時テーブル・トランジェントテーブルなどの公式分類とは別物です。また、Snowflake公式ドキュメントに登場する「インタラクティブテーブル(Interactive Tables)」とも別の概念なので混同しないようご注意ください。

そんなときに頼りになるのが、SnowflakeのSEARCH OPTIMIZATION SERVICE(検索最適化サービス)です。今回は、この機能をやさしく解説していきます!

⚠ 利用前提: SEARCH OPTIMIZATION SERVICEは Enterprise Edition以上 で利用できる機能です。Standard Editionでは ALTER TABLE ... ADD SEARCH OPTIMIZATION を実行してもエラーになります。検証前に利用中のSnowflakeエディションを必ず確認しましょう。

Snowflake SEARCH OPTIMIZATIONで数億行の反復検索テーブルから1行を高速抽出するイメージを示す概念図

SEARCH OPTIMIZATIONとは?

検索最適化サービスは、テーブルに対して専用の検索アクセスパス(インデックスのような構造)を裏側で構築してくれる機能です。等価検索 (=)、IN句、部分一致検索 (LIKE/ILIKE)、VARIANT列のフィールド検索、GEOGRAPHY型の地理検索など、選択的な絞り込みを大幅に高速化してくれます。

Snowflakeはもともとマイクロパーティションによって自動的にプルーニング(不要部分の読み飛ばし)してくれますが、検索条件の値があちこちに散らばっていると、プルーニングが効きにくくなります。そこで検索最適化サービスが、「どのマイクロパーティションにどの値があるか」のメタ情報を保持し、目的の行へ最短ルートで到達できるようにするわけです。

どんなクエリに効くのか

公式ドキュメントを参考にすると、検索最適化が特に向いているのは次のような条件のクエリです。導入前にこれらに当てはまるかチェックしましょう。

  • 主クラスタキー以外の列で絞り込んでいる(クラスタリングキーが効かない検索)
  • 顧客ID・注文ID・セッションIDなど高カーディナリティな列で検索している(目安:フィルター列の少なくとも1つが10万以上のユニーク値を持つ)
  • 1件〜少数件だけを返すポイントルックアップが中心
  • 最適化前のクエリが数秒以上かかっている
  • 既存のクラスタリングキーでは絞り込みにくい列で検索している

逆に、フルスキャン中心の集計クエリや、マテリアライズドビューで集計済みのケースには向きません。

事前にコスト見積もりをする

本番テーブルにいきなり有効化する前に、SYSTEM$ESTIMATE_SEARCH_OPTIMIZATION_COSTS 関数でコスト見積もりを取っておくのが安全です。

-- ORDERS テーブルに EQUALITY(order_id, customer_id) を付けた場合のコスト見積もり
SELECT SYSTEM$ESTIMATE_SEARCH_OPTIMIZATION_COSTS(
  'ORDERS',
  'EQUALITY(order_id, customer_id)'
);

-- 部分一致検索 (SUBSTRING) を付ける場合
SELECT SYSTEM$ESTIMATE_SEARCH_OPTIMIZATION_COSTS(
  'CUSTOMERS',
  'SUBSTRING(email)'
);

とくに SUBSTRING検索VARIANT列に対する有効化は、ストレージ・メンテナンスコストが大きく膨らみやすいため、必ず事前に見積もりをチェックしましょう。なお公式ドキュメントでも触れられていますが、見積もりはあくまで概算で、実際のコストは見積もりから大きくずれることがあります。

必要な権限

検索最適化を追加・設定・削除するには、次の権限が必要です。実務ではここで詰まりやすいので最初に整理しておきましょう。

  • 対象テーブルの OWNERSHIP 権限
  • 対象スキーマに対する ADD SEARCH OPTIMIZATION 権限

一方、検索最適化が有効化されたテーブルを SELECT するだけの利用者には、追加の専用権限は不要です(通常の SELECT 権限があればOK)。RBACに従って次のように権限を付与します。

-- 開発ロールにスキーマ単位で権限を付与
GRANT ADD SEARCH OPTIMIZATION ON SCHEMA sample_db.public
  TO ROLE developer_role;

-- 個別テーブルのオーナーシップ移譲が必要な場合
GRANT OWNERSHIP ON TABLE sample_db.public.orders
  TO ROLE developer_role
  COPY CURRENT GRANTS;

使い方:ALTER TABLEで有効化する

権限と見積もりが整ったら、ALTER TABLEで有効化します。

-- ① テーブル全体に有効化(検証・学習用にシンプル)
ALTER TABLE customers ADD SEARCH OPTIMIZATION;

-- ② 等価検索 (=, IN) を高速化したい列だけを指定(本番推奨)
ALTER TABLE orders
  ADD SEARCH OPTIMIZATION ON EQUALITY(order_id, customer_id);

-- ③ LIKE / ILIKE / 正規表現の部分一致検索を高速化
ALTER TABLE customers
  ADD SEARCH OPTIMIZATION ON SUBSTRING(email);

-- ④ VARIANT列のJSONフィールドにも対応
ALTER TABLE events
  ADD SEARCH OPTIMIZATION ON EQUALITY(payload:user_id);

-- ⑤ 状態を確認
SHOW TABLES LIKE 'customers';
DESCRIBE SEARCH OPTIMIZATION ON customers;

①のテーブル全体への有効化はシンプルで初心者向けの書き方ですが、本番環境では検索に使う列だけを指定する②③④の書き方が推奨されています。不要な列まで検索アクセスパスを作ると、ストレージ・メンテナンスコストが膨らむためです。

また、LIKE や ILIKE などの部分一致検索を高速化したい場合は、EQUALITYではなくSUBSTRINGを指定する必要があります。EQUALITYは等価・IN検索、SUBSTRINGは部分文字列検索、GEOはGEOGRAPHY検索と、それぞれ対応する検索メソッドが異なる点に注意してください。

Snowflake SEARCH OPTIMIZATIONをALTER TABLEで有効化しEQUALITY・SUBSTRING・VARIANT列に適用するSQL構文例

有効化してもすぐには効かない

ADD SEARCH OPTIMIZATION を実行してもクエリが即時に高速化されるわけではありません。Snowflakeはバックグラウンドで検索アクセスパスを構築し、データが投入されメンテナンスが追いつくにつれて段階的に効果が出てきます。

有効化直後にベンチマークを取ると「効いていない」と勘違いしがちなので、まずは状態を確認してから効果検証しましょう。

-- 検索アクセスパスの構築状況を確認
DESCRIBE SEARCH OPTIMIZATION ON customers;
-- → "active" や "in progress" 等のステータスが表示される

効果確認:Query Profileで「Search Optimization Access」を見る

あるクエリで実際に検索最適化が使われたかどうかは、SnowsightQuery Profileで確認できます。クエリ実行後、Query Profileのオペレーター一覧に 「Search Optimization Access」というノードが表示されていれば、検索最適化が使われた証拠です。

ただし、検索最適化を有効化していても、どのクエリで使うかはSnowflakeのオプティマイザが自動で判断します。条件によっては通常スキャンが選ばれることもあるため、効果がない場合はQuery Profileで実際に使われているかを確認するのが基本になります。

反復検索されるテーブルでの活用シーン

検索最適化サービスが特に効くのは、こんなパターンです。

  • 顧客マスタや商品マスタ:大量のレコードからキーで1件だけ取り出す
  • イベントログ・監査ログ:特定のユーザーIDやセッションIDの行動だけを抽出
  • BIダッシュボード:同じテーブルに何度も選択的なクエリが飛ぶ
  • VARIANT型のJSONデータ:ドット記法で深い階層を絞り込みたいケース
  • メールアドレスやユーザー名のLIKE検索:SUBSTRINGを使った部分一致でも高速化できる

注意点:コストとのバランス

便利な一方で、検索最適化サービスは追加のストレージとメンテナンス用クレジットを消費します。次の点を意識しましょう。

  • 更新頻度の高いテーブルは維持コストが上がる
  • フルスキャンばかりのテーブルや、マテリアライズドビューで集計済みのケースには不向き
  • 本番では ON EQUALITY(...)ON SUBSTRING(...)列を絞って指定するとコスト効率が良い
  • 有効化前に SYSTEM$ESTIMATE_SEARCH_OPTIMIZATION_COSTS でコスト見積もりを取る

頻繁にデータが変わるなら動的テーブルと組み合わせ、安定後のテーブルに検索最適化を付けるのも一つの手です。

まとめ

反復的にポイントルックアップされるテーブルには、SEARCH OPTIMIZATIONがまさにうってつけ。ALTER TABLE 1行で有効化でき、ID検索やJSONフィールドの絞り込みを劇的に高速化してくれます。

導入前のチェックリストとしては、(1) Enterprise Edition以上か、(2) 必要な権限(OWNERSHIP + ADD SEARCH OPTIMIZATION)があるか、(3) コスト見積もりを取ったか、(4) 列を絞って指定しているかを必ず確認しましょう。コストとのバランスを見ながら、ここぞという場面で使いこなしてください!

参考リンク

関連記事