PLAY DEVELOPERS BLOG

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

Snowflake のクラスタリングキーを設定したらデータの集計が爆速になった話

こんにちは、SaaS プロダクト開発部の池田です。 主に視聴動向データの分析を行うサービスの開発・運用を担当しております。

視聴動向データの分析基盤で採用している Snowflake において、クラスタリングキーの設定をすることで、クエリの応答速度が爆速になった話を紹介したいと思います。

もし、Snowflake をご利用中で、クラスタリングキーの設定をした覚えがない人は必見です!この記事を読んだ後は、クラスタリングキーを設定したくてウズウズしていると思います(笑)

そもそも Snowflake の導入をご検討中の方は、以前丸山が紹介した記事がとても役立つと思うので参考にしてください。 developers.play.jp

背景

冒頭でもある通り、私が担当している視聴動向データの分析サービスでは、Snowflake を採用しており、Snowflake の本番運用を開始してから既に 1 年半ほど経過しました。現在では、時間の経過と共に多くのデータが蓄積されています。 これは喜ばしいことではありますが、データの増加やサービスの使用される頻度が増えたことに伴い、パフォーマンスの低下が目立つようになってきました。

具体的には、Snowflake で実行されるクエリの処理時間が長くなり、場合によっては 2 分ほどかかるクエリも出てきました。

この視聴動向データの分析基盤は、事業者がデータの集計や分析を行い、ビジネス上の意思決定に使われます。すぐに分析が行えない場合は、事業者のストレスになります。そのため、少しでもクエリの処理を速くすることが不可欠になります。

このような状況を改善するために、まずは、なるべく追加のコストをかけずに、クエリの処理時間を短縮する方法を検討しました。仮想ウェアハウスのサイズを増やすことで速度は向上しますが、コストを抑えるために、クラスタリングキーの設定に着手しました。

クラスタリングキーを設定してみよう

それでは、実際にクラスタリングキーを設定する方法を見てみましょう!

でもその前に、クラスタリングキーとは何でしょうか?

実は、これを理解するためには「マイクロパーティション」という概念を知っておくことが大切です。 なので、クラスタリングキーの話に入る前に、マイクロパーティションについて触れておきます。

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

マイクロパーティションとは、Snowflake 内の各テーブルのデータを自動的に小さな単位に分割して保存し、管理する方法です。これにより、Snowflake はデータを効率的に処理し、クエリのパフォーマンスを向上させます。

デフォルトでは、データがテーブルに挿入もしくは、ロードされた順に従って、マイクロパーティションとして自動的に分割、保存します。

マイクロパーティション概要(Snowflake の公式ドキュメントから引用)*1

上の図は、テーブルのデータがどのようにしてマイクロパーティションに分割されているかを示しています。左の t1 テーブルの各行は、上から順に 4 つのマイクロパーティションに分割されて保存されています。例えば、テーブルの上から 2 行目のデータは、Micro-partition 1 に保存されていることがわかります。

Snowflake 内で最初にクエリを受け取るクラウドサービスレイヤは、各マイクロパーティションの最小値や最大値など、保存された行データに関連するメタデータを管理しています。

図の内、date の最小値や最大値のメタデータは次のようになります。

パーティション名 最小値 最大値
Micro-partition 1 11/2 11/2
Micro-partition 2 11/2 11/3
Micro-partition 3 11/2 11/4
Micro-partition 4 11/3 11/5

11/2 のデータを取得したい場合は、全てのデータ(Micro-partition 1 ~ 4)をスキャンするのではなく、必要なマイクロパーティション(Micro-partition 1 ~ 3)のみをスキャンすることで、効率良くデータの取得を行います。

ちなみに、これは Snowflake でのデータ処理を効率化する技術で、プルーニング と呼ばれます。この方法では、各マイクロパーティションに含まれるデータの範囲(最大値や最小値)を参照して、クエリに不要なパーティションをスキップします。

結果として、読み込むデータ量が減り、クエリの実行が高速化されます。

クラスタリングキーとは

話は戻りますが、クラスタリングキーとは、Snowflake において、テーブル内のデータをより効率的に整理するために使われる列または式のことです。

先ほど、デフォルトでは、データがテーブルに挿入もしくは、ロードされた順に従って、マイクロパーティションとして自動的に分割、保存されると述べましたが、クラスタリングキーを設定することで、このキーに基づいてデータをマイクロパーティションに分割、保存させることができます。

つまり、自分のテーブルのデータ構造に合わせた、より最適化されたデータ管理を実現させることができます!

クラスタリング概要(Snowflake の公式ドキュメントから引用)*2

上の図は、datetype をクラスタリングキーとして指定した後の状況が示されています。クラスタリングキーを設定することで、同じ datetype のデータが集まり、より整理された状態になっていることがわかります。

例えば、以前は 11/2 のデータを取得するためには、複数のマイクロパーティション(Micro-partition 1 〜 3)をスキャンする必要がありましたが、クラスタリングキーを設定した後では、より少ないマイクロパーティション(Micro-partition 1 〜 2)だけのスキャンで済むようになります。

さらに、11/2 のデータかつ type が 2 であるデータを取得するような場合においても、クラスタリングキーの設定により必要なマイクロパーティションのスキャン数が減少し、効率的なデータアクセスが可能になります。

実際に設定するSQL

実際に設定した SQL を紹介します。 クラスタリングキーは、各テーブルに対して設定する必要があります。 ここでは、視聴動向データの分析サービスでよく使用される sessions テーブルを例に挙げます。

クラスタリングキーの設定の有無の確認

念の為、現在の設定状況を確認しましょう。 以下を実行後、cluster_by カラムに何も表示されていなければ、クラスタリングキーは未設定です。

SHOW TABLES LIKE 'sessions';

ちなみに、cluster_by カラムに値が表示されていれば、設定されているので、クラスタリングキーを設定後に再度実行してみて、本当にクラスタリングキーが設定されているかどうかもご確認することをおすすめします。

クラスタリングキーの設定

では、実際にクラスタリングキーの設定を行いましょう。

以下のように、ALTER TABLE コマンドを使います。テーブル作成時に、CREATE TABLE コマンドを使って設定することもできます。

ALTER TABLE sessions CLUSTER BY (CUSTOMER_ID, TO_DATE(SESSION_START));

前提として、今回は CUSTOMER_IDSESSION_START という 2 つのカラムをクラスタリングキーとして設定しています。

なぜ、この 2 つのカラムを選んだかというと、私たちの視聴動向データの分析基盤でのデータ取得の際に、必ず使用される(WHERE 句に含まれる)からです。

視聴動向データの分析基盤では、事業者ごとに発行される CUSTOMER_ID および、セッション開始時刻を表す SESSION_START のカラムがテーブルに格納されています。データを取得する場合は、特定の事業者の特定の期間のデータを抽出するという取得方法になるため、必ずこの 2 つのキーを WHERE 句 に含めています。

例えば、以下のような WHERE 句をつけてデータの取得をします。

WHERE CUSTOMER_ID = 'XXXX' AND SESSION_START BETWEEN '2023-12-12 00:00:00.000' AND '2024-01-11 23:59:59.999'

Snowflake ではフィルターで最も使用される列を優先的にクラスタリングキーに設定することを推奨しています。これは、効果的なプルーニングを行えるようにするためです。 そのため、CUSTOMER_ID と、SESSION_START をクラスタリングキーとして設定しました。

SESSION_START ではなく、TO_DATE(SESSION_START) としている理由についてですが、Snowflake の料金を少しでも抑えるためです。

クラスタリングキーを設定後、クラスタリング自体は、自動で行われます。その際に、クラスタリング処理に対して費用がかかります。以下の Snowflake の公式ドキュメントにもある通り、設定したクラスタリングキーのカーディナリティが高い(データの種類が多い場合)場合は、クラスタリングの処理費用が高くなるので、カーディナリティを低くする(データの種類を少なくする)工夫をすることが推奨されています。

一般に、列(または式)のカーディナリティが高い場合、その列でのクラスタリングの維持はより高価になります。

一意のキーでのクラスタリングのコストは、特にそのテーブルの主な使用例ではないポイントルックアップの場合、そのキーでのクラスタリングの利点を上回る場合があります。

カーディナリティが非常に高い列をクラスタリングキーとして使用する場合は、個別の値の数を減らすために、キーを列ではなく列の式として定義することをSnowflakeはお勧めします。式は、各パーティションの最小値と最大値でプルーニングが有効になるように、列の元の順序を保持する必要があります。

例えば、ファクトテーブルに、多くの離散値(テーブル内のマイクロパーティションの数よりも多く)を含む TIMESTAMP 列 c_timestamp がある場合、タイムスタンプではなく日付に値をキャストすることで、列にクラスタリングキーを定義できます(例: to_date(c_timestamp))。これにより、カーディナリティが合計日数に削減され、より優れたプルーニング結果が通常生成されます。

別の例として、 TRUNC 関数とスケールの負の値(例: TRUNC(123456789, -5))を使用して、数値をより少ない有効桁数に切り捨てることができます。

また、以下の Snowflake の公式ドキュメントにもある通り、複数のクラスタリングキーを設定する場合は、最低カーディナリティから最高カーディナリティの順で設定することが推奨とされています。そのため、CUSTOMER_IDTO_DATE(SESSION_START) の順に設定しています。我々のシステムで実際の取得時にも、特定の事業者の特定の期間のデータを抽出するというような取得方法になるため、この設定順が一番効率が良いと考えています。

テーブルに複数列のクラスタリングキーを定義する場合は、 CLUSTER BY 句で指定される列の順序が重要です。原則として、Snowflakeは列を 最低 カーディナリティから 最高 カーディナリティに並べることを推奨しています。一般に、低いカーディナリティ列の前に高いカーディナリティ列を配置すると、後者の列でのクラスタリングの有効性が低下します。

結果

クラスタリングキーを設定したことで、いくつか利点があったので紹介します。

クエリ応答速度の向上

クラスタリングキーの設定前後で同じクエリを実行したときの処理時間を比較した結果を下の図に示します。

Query 1 ~ 5 は、実際にアプリケーションから実行されているクエリの内、無作為にピックアップしたものになります。

水色のクラスタリングキー設定前に比べて、赤色のクラスタリングキー設定後の方が、数倍以上速くなっていることがわかります。具体的には、最大で 31 倍の速度向上が見られ、全体的にも爆速になっています。

なぜ速くなったのか

これは、データ取得時のスキャン量が減少したからだと考えます。

スキャン量の比較

Query 4 は、データ量が多いテーブルに対して実行するクエリなのですが、そのクエリについて、クラスタリングキー設定前後のクエリのパフォーマンスを比較してみました。

Snowflake の管理画面から、クエリプロファイルの統計が確認できるので、その結果を以下に示します。

スキャン量が大幅に減少していることがわかります。 具体的には、データベース内の全パーティションの中で、実際にクエリで調べる必要のあるパーティションの割合(パーティションの合計に対するスキャン済みパーティションの割合)が小さくなっています。これは、クラスタリングキーがデータをより効率的に整理しているため、関連しないデータを素早くスキップ(プルーニング)できるようになったことを意味します。

結果として、必要なデータだけに素早くアクセスでき、全体的なデータ処理が速くなっています。

コストの低下

以下の図は、クラスタリングキー設定前後の日付ごとの Snowflake の料金です(赤枠の部分がクラスタリングキーを設定した日になります)。

SERVERLESS_TASK が設定前に比べて、半分ほど減っているのがわかります。データの効率的な配置とアクセスによってクエリ処理が高速化されたためだと考えられます。

今回のケースでは、WAREHOUSE_METERING(ウェアハウスによって消費された料金)がほぼ変わらないですが、クエリの高速化により、ウェアハウスの立ち上げ時間が少なくなる場合においては、そこの料金も下がるかと思います。

注意点

クラスタリングキーを設定する際に、いくつか注意点があるのでご紹介します。

クラスタリングキーの設定はすぐに反映されない

クラスタリングキーを設定後、すぐに反映されるわけではありません。設定後は、一定時間待ってからどれだけ速くなったかを確認することをおすすめします。

再クラスタリング費用がかかる

クラスタリングキーを設定すると、再クラスタリングが自動で行われますが、これには費用がかかります。そのため、再クラスタリングによる費用とクエリの速度向上や他の費用削減度合いを天秤にかけて考える必要があります。 また、「コストの低下」で示した図で分かる通り、適用直後は、これまで蓄積されたデータの再クラスタリングが行われるので、適用日は通常以上にコストがかかってしまいます。

まとめ

Snowflake 自体が元々高速なので、これ以上速くなることがあるのだろうかと半信半疑でしたが、それを覆す爆速ぶりでした(笑) Snowflake を使うなら、真っ先に設定するべき内容かと思います!

大規模なシステムであればあるほど、効果が顕著に現れ、恩恵は大きい思うので、是非、皆さんもお試しください!!!