Snowflake マイクロパーティションとデータクラスタリングの解説 | Snowflake Advent Calendar 2019 #SnowflakeDB

2019.12.18

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Snowflakeの速さの秘訣はプルーニングであり、効果的にプルーニングするにはデータクラスタリングが必要です。クラスタ化したデータを効率的に扱えるデータファイルがマイクロパーティションとなります。今日はSnoflakeの基礎の基礎、マイクロパーティションとデータクラスタリングの解説します。

マイクロパーティション

マイクロパーティションとは

マイクロパーティションは、Snowflakeのテーブルのデータを格納するファイルです。例えば、Stageに配置したデータファイルはCOPYコマンドでロードすると自動的に取り込み順序に基づいて連続したマイクロパーティションに保存されます。マイクロパーティションは、イミュータブル(変更不可能)な特性を持つので、更新する度に新しいファイルが作成します。

  • テーブルデータを保持する連続したストレージユニット
    • 50〜500 MBの非圧縮データを圧縮して、一般的に16MB(圧縮)になる
  • テーブル毎に複数のマイクロパーティションが作成される
  • IMMUTABLE
  • サービス層は、すべてのマイクロパーティションに関するメタデータを保存する
    • MIN / MAX(各列の値の範囲)
    • distinct valuesの数

特長

  • DML操作(DELETE、UPDATE、MERGEなど)は、潜在的なマイクロパーティションメタデータを利用して、テーブルのメンテナンスを簡素化します
  • テーブルからすべての行を削除するなどの一部の操作は、メタデータのみの操作です
  • MIN、MAX、COUNTなどの集計操作はメタデータのみの操作です

データクラスタリング

ナチュラルデータクラスタリング

データクラスタリングとは、データを分類することを表します。ナチュラルデータクラスタリングは、Stageからロードした順に基づいてデータを分類します。例えば、毎日データをロードすると自然と日付順にデータが配置されますが、更に日付と1つ以上のカラムとは相関しているという特性を活かしてデータを分類します。

  • データがテーブルにロードされると、データをロードされた順にマイクロパーティションが作成される
  • データロードした日付と1つ以上のカラムとは相関しているという特性を活かす
    • シーケンシャルフィールドを持つテーブル
    • 日付フィールドを持つテーブル

どうやって決定するのか?

1回のデータロードでソースデータを読み取り、マイクロパーティションに書き込みます。次にソースデータの構成が、マイクロパーティションで表現される値の範囲を決定します。

例えば、

  • ソースデータには特定の日の行が含まれ、その日のデータは連続したマイクロパーティションになる
  • ソースデータには1か月または1年の行が含まれ、マイクロパーティションにはその月または年内の日付の最大値/最小値があります

クラスタリングキーによるクラスタ化テーブル

前述の通り、全てのテーブルはデータの取り込みに基づいたナチュラルデータクラスタリングを利用できますが、任意のキーでクラスタリングすることも可能です。

  • 特定のカラムまたは式で「キー」をクラスタリングし、その後
  • 必要に応じてバックグラウンドで再クラスター化
  • 最大1〜3個のキーを使用することが推奨、キーが多いことが良いことではありません
  • 低いカーディナリティから高いカーディナリティの順に設定

クラスタリングキーは、クラスタリングに使用するカラムまたは式を指定します。クラスタリング後、同じクラスタリングキーのデータは同じマイクロパーティションにロードされます。クラスタリングテーブルのメンテナンスはSnowflake自動クラスタリングサービスによって処理され、1秒ごとに請求されます。

常にクラスタ化テーブルが良いとは限らない

クラスタリングキーはすべてのテーブルにとって良い選択とは限りません。

  • 自動クラスタリングはクレジットを消費します
    • 再クラスタリングはストレージコストも増加させます
    • テーブルをロードした後、クラスターキーを追加するのに費用がかからない
    • 自動クラスタリングを無効にすることができます
  • クラスタリングキー選定のポイント:
    • 数テラバイト規模のテーブルでは、クラスタリングのメリットが最も大きくなります。
    • 特に、DMLがこれらの表で定期的に実行される場合は有効です
    • 頻繁に変更されないテーブルは、再クラスター化のコストが低くなります
    • 時間経過とともにクエリのパフォーマンスが著しく低下するテーブル

クラスタキーの設定例

-- テーブル作成時にクラスタキーとなるカラム名を指定する例
CREATE TABLE t1 (c1 date, c2 string, c3 number)
CLUSTER BY (c1, c2);

-- テーブル作成時にクラスタキーとなる式を指定する例
CREATE TABLE t2 (c1 timestamp, c2 string, c3 number)
CLUSTER BY (TO_DATE(c1), SUBSTRING(c2, 0, 10));

-- 既存のテーブルにクラスタキーとなるカラム名を指定する例
ALTER TABLE t1 
CLUSTER BY (c1, c3);

-- 既存のテーブルにクラスタキーとなる式を指定する例
ALTER TABLE t2
CLUSTER BY (SUBSTRING(c2, 5, 10), TO_DATE(c1));

パーティションプルーニング

クエリでプルーニングする

これまでデータをなぜデータをクラスタ化して保存したかというと、クエリでプルーニングをしたかったからです。クラスタ化の目的は不必要なデータの読み取りを削減(プルーニング)するためです。(プルーニングとは英語で「剪定(せんてい)」の意で、木の余計な枝を切るように、余計なデータを切ってしまうことの比喩的表現です。)

  • データがテーブルに挿入/ロードされると、プロセス中に作成された各マイクロパーティションのクラスタリングメタデータが収集および記録されます
  • Snowflakeはこのクラスタリング情報を活用して、クエリ中のマイクロパーティションの不要なスキャンを回避します
    • これらのカラムを参照するクエリのパフォーマンスを大幅に向上します

プルーニングの例

例えば、3,000億件のレコードが722,313個のパーティションファイルに分割されていた場合、クエリは「1840」を含むパーティションファイルのみを読み取りで済むため、余計なファイルの読み取りや処理が不要になり高速になります。

最後に

Snowflakeは効率的にプルーニングするためにデータをクラスタリングしてマイクロパーティションに格納しているので、不要なファイルの読み取りを効果的に削減できます。Snowflakeはクラスタキーを設定しなくてもナチュラルオーダーでデータをプルーニングできますが、分類したいキーが明らかな場合はクラスタキーを指定した方がベターです。

一般的なデータウェアハウスやデータレイクにクラスタキー相当の設定をすると同様にプルーニングできるようになりますが、事前のETLやデータロード時のソートなどのコストが発生します。一方、Snowflakeはロード時にナチュラルーオーダーでロードするので非常に高速です。データのクラスタリングやソートはフルマネージドサービスレイヤがバックグラウンドで非同期実行して、常に最適なパフォーマンスが得られる状態を維持します。大規模なテーブルの場合、ほとんどのデータがクラスタ化されているため、クエリが常に高速になります。しかし、自動クラスタリングはクレジットの消費やストレージコストも生じるのでユースケースに応じて使い分けるということも忘れない方が良いでしょう。