目次
- はじめに
- Snowflakeにおける最適化の前提
- クラスタリングキーとは何か
- クラスタリングキーとインデックスの違い
- 効果が出る条件と出ない条件
- クラスタリングキーと物理配置の関係
- 検証
- 実務でどう使うか
- まとめ
1. はじめに
Snowflakeでは
「クラスタリングキーを指定すればクエリは速くなる」
と思われがちです。
しかし実務では、次のように感じるケースが少なくありません。
- 効果がよく分からない
- 指定しても、すぐに変化が出ない
- 期待したほど速くならない
この原因は、
クラスタリングキーの指定方法が間違っているから ではありません。
多くの場合、
クラスタリングキーの「役割の理解」がずれている ことが原因です。
本スライドでは、
- クラスタリングキーの正体
- Snowflake における正しい最適化の考え方
を整理し、
「なぜ効かないように見えるのか」 を構造的に説明していきます。
📝 クラスタリングキーは
「即効性のある高速化スイッチ」ではなく、
物理配置を“整えていくための仕組み” である点が重要です。
2. Snowflakeにおける最適化の前提
Snowflakeの最適化を理解するうえで、
まず押さえておくべき前提があります。
Snowflake は「行単位」でデータを探さない
Snowflake では、
PostgreSQL や Oracle のように 行単位でデータを探しにいく ことはしません。
データは常に
micro-partition 単位 で読み込まれます。
最適化の中心は「探す速さ」ではない
Snowflake における最適化の本質は以下にあります。
- 「速く探す」こと ではない
- 読まないデータをいかに増やすか
micro-partition は事前にふるい落とされる
各 micro-partition には、以下の メタデータ が保持されています。
- MIN / MAX
- NULL の有無
- 行数 など
クエリ実行時、
条件に合わない micro-partition は 実データを読む前に除外 されます。
実行時間とコストは「読んだ量」で決まる
Snowflake では、実行時間 、クエリコスト
のどちらも、どれだけの micro-partition / Bytes を読んだか
に強く依存します。
そのため Snowflake では
「実行時間が短いか」よりも
「どれだけ読まれているか」 を見ることが重要になります。
3. クラスタリングキーとは何か
Snowflakeにおけるクラスタリングキー は、
データの並び方に関する「方針」を指定する仕組み です。
クラスタリングキーを指定すると、
指定した列の値が近いデータ同士が
近い micro-partition に集まりやすく なります。
インデックスではない
クラスタリングキーとは、
- インデックスではない
- 行を高速に検索する仕組みではない
そのため、
指定直後に効果が出るものではありません。
Snowflake における位置づけ
Snowflake は、
クラスタリングキーを
物理配置を自動調整するためのヒント
として扱います。
目的
クラスタリングキーの目的は、
micro-partition のプルーニングが効きやすい状態を維持すること
です。
📝 「速く探す」ための仕組みではなく、
「読まないデータを増やす」ための仕組み です。
4. クラスタリングキーとインデックスの違い
| 観点 | クラスタリングキー(Snowflake) | インデックス(PostgreSQL など) |
|---|---|---|
| 目的 | データの物理配置を整えやすくする | 行に高速に到達する |
| 対象単位 | micro-partition | 行(タプル) |
| 即効性 | なし(徐々に効く) | あり(作成直後から) |
| 効果の出方 | プルーニングが効きやすくなる | 検索・結合が直接速くなる |
| 指定の意味 | 配置に関する方針 | 検索用のデータ構造 |
| 管理主体 | Snowflake が自動管理 | 利用者が設計・管理 |
| 期待値 | 将来のスキャン量削減 | 即時の実行時間短縮 |
5. 効果が出る条件と出ない条件
Snowflake のクラスタリングキーは、
即座にデータを並べ替える仕組みではありません。
指定しても、すぐには変わらない
クラスタリングキーを指定しても、
既存データの配置が すぐに再配置されるわけではありません
Snowflake は、常に並び替えを行うわけではないためです。
データの並びは時間とともに崩れる
実務では、INSERT 、UPDATE
によって、データの並びは 時間とともに自然に崩れていきます。
クラスタリングキーは、その状況に対して
常に即応する仕組みではありません。
クラスタリングキーの扱われ方
クラスタリングキーは以下の点が重要です。
- 命令ではない
- 方針として扱われる
効果が出るかどうかは条件次第
クラスタリングキーの効果は以下に依存します。
- データ量
- データの増え方
- クエリ条件
そのため、
「指定したのに速くならない」
という状況は、珍しいことではありません。
6. クラスタリングキーと物理配置の関係
Snowflakeでは、
データは micro-partition 単位 で読み込まれます。
micro-partition と物理配置
各 micro-partition には以下が保持されています。
- 列ごとの MIN / MAX
- その他のメタデータ
値が 物理的にまとまっているほど、
不要な micro-partition を事前に除外(プルーニング)しやすく なります。
クラスタリングキーの役割
クラスタリングキーは、
この 「値のまとまり」 を
維持しやすくするための仕組み です。
- 物理配置が整っている
→ プルーニングが効き、読む量が減る - 物理配置が崩れている
→ クラスタリングキーを指定しても効果は出にくい
再配置(再クラスタリング)とは
Snowflake では、
データは 基本的に追加順 で物理配置されます。
クラスタリングキーが指定されている場合、
必要に応じて バックグラウンドで
再配置(再クラスタリング)が行われます。
ただし、以下の点には注意が必要です。
- Snowflake 側の判断で実行される
- 常時行われるわけではない
- 即時に実行されるわけでもない
再配置の目的とコスト
再配置の目的は、
物理配置の乱れを抑え、
プルーニングが効きやすい状態を維持すること
なお、
再配置にはクレジット消費が発生します。
(必要時のみ。テーブル、変更頻度に依存)
7. 検証
検証の目的
Snowflakeにおいて、
クラスタリングキーが実際に適用された場合 と
指定していない場合 で、
以下にどの程度の差が出るかを確認します。
- プルーニング効率
- スキャン量
検証の前提条件
- 使用する SQL は同一
- 使用するデータは同一
- 件数・値の分布は完全に同じ
- Warehouse サイズは同一
異なるのは 物理配置のみ です。
差が出た場合、
クラスタリングキー適用による物理配置の変化 が原因と説明できます。
クラスタリングキーに関する前提
- クラスタリングキーは
物理配置を制御する「命令」ではない - Snowflake が必要と判断した場合にのみ、
再配置(再クラスタリング)が行われる - 再配置が行われた場合、
プルーニング効率に直接影響する
今回は、
クラスタリングキーが実際に適用されたケース を扱います。
検証に使用するデータ
- 行数:約 300 万行
- micro-partition 数:16
- データサイズ:数 MB 程度
列構成
- クラスタリングキー対象列
- category(26 種類)
- 日付列
- created_at
- ペイロード列
- 文字列
検証用テーブル構成
クラスタリングキーなし
T_RANDOM
- ランダム順で作成
- 同じ値が全体に散らばる
- プルーニングが効きにくい状態
クラスタリングキーあり
T_RANDOM_CLUSTERED
- ランダム順で作成
- クラスタリングキー(category)を設定
- 再配置により、
同じ値が近くに集まった状態
① 使用するクエリ(等価条件)
SELECT COUNT(*) FROM T_RANDOM WHERE category = 'A';
SELECT COUNT(*) FROM T_RANDOM_CLUSTERED WHERE category = 'A';
- 等価条件の複数値指定(IN)
- 対象データ範囲を意図的に拡張
- プルーニング効率の変化を確認
- キャッシュの影響を避けて実行
② 使用するクエリ(IN句)
SELECT COUNT(*) FROM T_RANDOM WHERE category IN ('A','B','C','D','E');
SELECT COUNT(*) FROM T_RANDOM_CLUSTERED WHERE category IN ('A','B','C','D','E');
- 等価条件の複数値指定(IN)
- 対象データ範囲を意図的に拡張
- プルーニング効率の変化を確認
- キャッシュの影響を避けて実行
クリックして展開(検証用SQL一式)
-- 検証テーブルの元となるデータ
CREATE OR REPLACE TABLE BASE_DATA AS
WITH gen AS (
SELECT
SEQ4() AS id
FROM TABLE(GENERATOR(ROWCOUNT => 3000000))
)
SELECT
id,
CHR(65 + MOD(id, 26)) AS category,
DATEADD('day', MOD(id, 365), '2024-01-01'::DATE) AS created_at,
RPAD(TO_VARCHAR(id), 200, 'x') AS payload
FROM gen;
-- ① 値が散らばる配置(ランダム)
CREATE OR REPLACE TABLE T_RANDOM AS
SELECT * FROM BASE_DATA
ORDER BY RANDOM();
-- ② 値が散らばる配置(ランダム)クラスタリングキー指定
CREATE OR REPLACE TABLE T_RANDOM_CLUSTERED AS
SELECT * FROM BASE_DATA
ORDER BY RANDOM();
ALTER TABLE T_RANDOM_CLUSTERED CLUSTER BY (category);
-- キャッシュ無効(必要に応じて)
-- ALTER SESSION SET USE_CACHED_RESULT = FALSE;
-- 検証クエリ(等価条件)
SELECT COUNT(*) FROM T_RANDOM WHERE category = 'A';
SELECT COUNT(*) FROM T_RANDOM_CLUSTERED WHERE category = 'A';
-- 検証クエリ(等価条件・複数値)
SELECT COUNT(*) FROM T_RANDOM WHERE category IN ('A','B','C','D','E');
SELECT COUNT(*) FROM T_RANDOM_CLUSTERED WHERE category IN ('A','B','C','D','E');
① 等価条件
SELECT COUNT(*) FROM T_RANDOM WHERE category = 'A';
SELECT COUNT(*) FROM T_RANDOM WHERE category = 'A';
検証結果(等価条件)
クラスタリングキーなし(T_RANDOM)
- Partitions scanned:16 / 16
- Bytes scanned:1.76 MB
- Query insights:特になし
すべての micro-partition をスキャンしており、
等価条件でもプルーニングはほぼ効いていない 状態です。
クラスタリングキーあり(T_RANDOM_CLUSTERED)
- Partitions scanned:2 / 3
- Bytes scanned:0.67 MB
- Query insights:Filter with clustering key
条件に合致する micro-partition のみがスキャンされており、
プルーニングが有効に機能 しています。
結果から分かること
Snowflakeでは以下が同じであっても、
物理配置の違い によって
スキャン対象は大きく変わります。
- SQL
- データ内容
- 件数
クラスタリングキーが適用されることで、
- 同じ値が近くの micro-partition に集約され
- 不要な partition を読み飛ばせる
結果として、以下の差が確認できました。
- Partitions scanned が大幅に減少
- Bytes scanned も削減
② 等価条件・複数値
SELECT COUNT(*) FROM T_RANDOM WHERE category IN ('A','B','C','D','E');
SELECT COUNT(*) FROM T_RANDOM_CLUSTERED WHERE category IN ('A','B','C','D','E');
検証結果(等価条件・複数値)
クラスタリングキーなし(T_RANDOM)
- Partitions scanned:16 / 16
- Bytes scanned:1.76 MB
- Query insights:特になし
IN 句で対象範囲を広げても、
すべての micro-partition をスキャン しています。
値が全体に散らばっているため、
プルーニングが機能していない 状態です。
クラスタリングキーあり(T_RANDOM_CLUSTERED)
- Partitions scanned:2 / 3
- Bytes scanned:0.67 MB
- Query insights:Filter with clustering key
IN 句(複数値)であっても、
必要な micro-partition のみをスキャン しています。
クラスタリングキーにより、
対象値が 近い partition に集約 されていることが分かります。
結果から分かること
Snowflakeでは、等価条件が
単一値(=)でも
複数値(IN)でも
クラスタリングキーが適用されていれば、
プルーニングは有効に機能 します。
条件を広げても以下を確認できました。
- 読む partition 数はほぼ増えず
- スキャン量も抑えられている
📝 物理配置が整っていれば、
IN 句でもスキャン量は増えにくい
という点が、この検証から読み取れます。
8. 実務でどう使うか
① クラスタリングキーを使うべき場面
以下ような条件がそろう場合、
Snowflakeのクラスタリングキーは検討対象になります。
- 等価条件(=) / IN 条件が頻繁に使われる
- データ量が多く、今後も増加が見込まれる
- Query Profile で
- Partitions
- Bytes
が多く読まれている
👉 「遅い」クエリではなく、
「読みすぎている」クエリを確認する のがポイント。
② キー選定の考え方
クラスタリングキーに向いているのは以下です。
- WHERE 句でよく使われる列
- 値がある程度まとまる列
具体例:
- カテゴリ系
- 日付系
- ID 系
👉 「並びたい列」ではなく、
「絞り込みに使われる列」 を選びます。
③ 効果確認の方法
クラスタリングキーの効果は、
実行時間だけで判断せず以下を比較します。
- Partitions scanned
- Bytes scanned
- Query insights
数値に変化がなければ、
効果は出ていない と判断します。
👉 効果がなければ、無理に使う必要はありません。
④ 使わない判断も設計の一部
次のような場合、
クラスタリングキーは 使わない判断 も妥当です。
- データ量が小さい
- クエリ条件が多様で固定されない
- 再配置(再クラスタリング)のコストが見合わない
👉 クラスタリングキーは万能ではありません。
9. まとめ
Snowflakeでは、
実行時間よりも「どれだけ読んだか」 が重要です。
同じ SQL、同じデータであっても、
物理配置の違い によって
スキャン量(Partitions / Bytes)は大きく変わります。
クラスタリングキーが適用されることで以下を確認できました。
- プルーニング効率が向上し
- 読むデータ量を削減できる
また、以下の条件であっても、
物理配置が整っていれば効果は維持 されます。
- 等価条件(=)
- IN 条件
実務では、以下を意識することが重要です。
- 「遅い」クエリではなく
- 「読みすぎている」クエリを確認する
📝 Snowflake の最適化は、
クエリを書くことではなく
データの「置き方」を意識することから始まります。



