クラスタリングキーとクラスタ化されたテーブル

一般に、Snowflakeはテーブル内に適切にクラスタ化されたデータを生成します。ただし、時間の経過とともに、特に DML が非常に大きなテーブル(行数ではなくテーブル内のデータ量で定義される)で発生するため、一部のテーブル行のデータが必要なディメンションに適切ににクラスタ化されなくなる場合があります。

基礎となるテーブルマイクロパーティションのクラスタリングを改善するために、キーテーブル列の行をいつでも手動でソートし、テーブルに再挿入できます。ただし、これらのタスクの実行は面倒で費用がかかる可能性があります。

代わりに、Snowflakeは、1つ以上のテーブル列/式をテーブルの クラスタリングキー として指定することにより、これらのタスクの自動化をサポートしています。定義されたクラスタリングキーを持つテーブルは、 クラスタ化済み と見なされます。

マテリアライズドビュー だけでなく、テーブルもクラスタ化できます。テーブルとマテリアライズドビューをクラスタリングするためのルールは、一般的に同じです。マテリアライズドビューに固有のいくつかの追加のヒントについては、 マテリアライズドビューとクラスタリングマテリアライズドビューのベストプラクティス をご参照ください。

注意

クラスタリングキーは、すべてのテーブルを 対象とするものではありません。テーブルのサイズと、テーブルのクエリパフォーマンスによって、テーブルのクラスタリングキーを定義するかどうかが決まります。特に、クラスタリングキーによるパフォーマンスの向上を確認するには、テーブルが十分な数の マイクロパーティション で構成されている必要があり、クラスタリングキーで定義された列はこれらのマイクロパーティションのサブセットを選択するのに十分なフィルタリングを提供します。

一般に、マルチテラバイト(TB)の範囲のテーブルは、これらのテーブルで DML が定期的/継続的に実行される場合、クラスタリングから最大の利点を享受します。

また、テーブルのクラスタ化を明示的に選択する前に、テーブルでクエリの代表セットをテストして、パフォーマンスベースラインを確立することを、Snowflakeは 強く お勧めします。

このトピックのセクション:

クラスタリングキーとは何ですか?

クラスタリングキーは、同じ マイクロパーティション 内のテーブル内のデータを共存させるために明示的に指定されたテーブル(またはテーブル上の式)の列のサブセットです。これは、順序が理想的ではなかった(データが挿入/ロードされた時点で)非常に大きなテーブルや、 DML によってテーブルの自然なクラスタリングが低下した場合に便利です。

テーブルのクラスタリングキーを定義するかどうかを判断するのに役立ついくつかの一般的なインジケータには次が含まれます。

  • テーブルのクエリの実行速度が予想よりも遅いか、時間が経つにつれて著しく低下します。

  • テーブルの クラスタリングの深さ は大きいです。

クラスタリングキーは、テーブルの作成時( CREATE TABLE コマンドを使用)またはその後( ALTER TABLE コマンドを使用)に定義できます。テーブルのクラスタリングキーは、いつでも変更または削除できます。

クラスタリングキーを定義する利点(非常に大きなテーブルの場合)

クラスタリングキーを使用して、同じマイクロパーティション内の同様の行を同じ場所に配置すると、次のような非常に大きなテーブルでいくつかの利点が得られます。

  • フィルタリング述語と一致しないデータをスキップすることにより、クエリのスキャン効率が向上しました。

  • クラスタリングのないテーブルよりも列圧縮が向上します。これは、他の列がクラスタリングキーを構成する列と強く相関している場合に特に当てはまります。

  • テーブルでキーが定義された後、キーをドロップまたは変更することを選択しない限り、追加の管理は必要ありません。(最適なクラスタリングを保証するための)テーブル内の行に対する今後のすべてのメンテナンスは、Snowflakeによって自動的に実行されます。

クラスタリングによりパフォーマンスは大幅に改善され、一部のクエリのコストを削減できますが、クラスタリングの実行に使用される計算リソースはクレジットを消費します。そのため、クエリがクラスタリングの実質的なメリットを享受する場合にのみクラスタリングする必要があります。

通常、クエリは、テーブルのクラスタリングキーでフィルター処理または並べ替えを行う場合、クラスタリングの恩恵を受けます。ソートは通常、 ORDER BY 操作、 GROUP BY 操作、および一部の結合に対して行われます。例えば、次の結合により、Snowflakeがソート操作を実行する可能性があります。

SELECT ...
    FROM my_table INNER JOIN my_materialized_view
        ON my_materialized_view.col1 = my_table.col1
    ...

この擬似例では、Snowflakeは my_materialized_view.col1 または my_table.col1 のいずれかの値をソートする可能性があります。例えば、 my_table.col1 の値がソートされている場合、マテリアライズドビューのスキャン中に、Snowflakeは my_table の対応する行をすばやく見つけることができます。

テーブルが頻繁にクエリされるほど、クラスタリングが提供する利益が増えます。ただし、テーブルが頻繁に変更されるほど、クラスタ化を維持するのに費用がかかります。したがって、一般的にクラスタリングは、頻繁にクエリされ、頻繁に変更されないテーブルに対して最も費用効果が高くなります。

注釈

テーブルのクラスタリングキーを定義した後、行が必ずしもすぐに更新されるとは限りません。Snowflakeは、テーブルが操作の恩恵を受ける場合にのみ自動メンテナンスを実行します。詳細については、 再クラスタリング (このトピック)および 自動クラスタリング をご参照ください。

クラスタリングキーを選択するための戦略

単一のクラスタリングキーには、1つ以上の列または式を含めることができます。ほとんどのテーブルでは、Snowflakeはキーごとに最大3または4列(または式)を推奨しています。3〜4を超える列を追加すると、利益よりもコストが増加する傾向があります。

クラスタリングキーに適切な列/式を選択すると、クエリのパフォーマンスに劇的な影響を与える可能性があります。ワークロードの分析により、通常、適切なクラスタリングキー候補が得られます。

Snowflakeは、以下の順序でキーに優先順位を付けることをお勧めします。

  1. 選択フィルターで最もアクティブに使用されるクラスタ列。日付ベースのクエリに関係する多くのファクトテーブル(例:WHERE invoice_date > x AND 請求日 <= y」)の場合、日付列を選択することをお勧めします。イベントテーブルでは、多数の異なるイベントタイプがある場合にイベントタイプが適切な選択になる場合があります。(テーブルに含まれるイベントタイプが少数の場合は、クラスタリングキーとしてイベント列を選択する前に、以下のカーディナリティに関するコメントを参照してください。)

  2. 追加のクラスタキーの余地がある場合は、結合述語で頻繁に使用される列、例:「FROM table1 JOIN table2 ON table2.column_A = table1.column_B」を検討してください。

通常、クエリを2つのディメンション(例: application_id 列と user_status 列)でフィルター処理する場合、両方の列でクラスタリングするとパフォーマンスが向上します。

列/式内の個別の値の数(つまり、カーディナリティ)は、クラスタリングキーとして選択する重要な側面です。以下を含むクラスタリングキーを選択することが重要です:

  • テーブルで効果的なプルーニングを可能にするために十分な数の個別の値。

  • Snowflakeが同じマイクロパーティション内の行を効果的にグループ化できるようにするための十分に少数の個別の値。

カーディナリティが非常に低い列(例:男性か女性かのみを示す列)では、最小限の排除しかできません。極端な場合、カーディナリティが非常に高い列(例: UUID またはナノ秒のタイムスタンプ値を含む列)も、通常、クラスタリングキーとして直接使用する候補には 適していません

ちなみに

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

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

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

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

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

ちなみに

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

場合によっては、 GROUP BY または ORDER BY 句で使用される列のクラスタリングが役立つ場合があります。ただし、通常、これらの列のクラスタリングは、フィルター操作または JOIN 操作で頻繁に使用される列のクラスタリングよりも有用性が低くなります。フィルター/結合操作で頻繁に使用される列と、 ORDER BY または GROUP BY 操作で使用される異なる列がある場合、フィルターおよび結合操作で使用される列を優先します。

再クラスタリング

クラスタ化されたテーブルで DML 操作(INSERT、UPDATE、DELETE、MERGE、COPY)が実行されると、テーブル内のデータのクラスタ化が低下する場合があります。最適なクラスタリングを維持するには、テーブルの定期的な再クラスタリングが必要です。

再クラスタリング中、Snowflakeはクラスタ化されたテーブルのクラスタリングキーを使用して列データを再編成し、関連するレコードが同じマイクロパーティションに再配置されるようにします。この DML 操作は、影響を受けるレコードを削除し、クラスタリングキーに従ってグループ化されたレコードを再挿入します。

注釈

Snowflakeの再クラスタリングは自動です。メンテナンスは必要ありません。詳細については、 自動クラスタリング をご参照ください。

ただし、特定のアカウントでは、手動の再クラスタリングは廃止されましたが、引き続き許可されています。詳細については、 手動再クラスタリング をご参照ください。

再クラスタリングのクレジットおよびストレージへの影響

Snowflakeのすべての DML 操作と同様に、再クラスタリングはクレジットを消費します。消費されるクレジットの数は、テーブルのサイズと再クラスタ化する必要があるデータの量によって異なります。

再クラスタリングは、ストレージコストももたらします。データが再クラスタ化されるたびに、テーブルのクラスタリングキーに基づいて行が物理的にグループ化されるため、Snowflakeはテーブルの 新しい マイクロパーティションを生成します。テーブルに少数の行を追加しても、それらの値を含むすべてのマイクロパーティションが再作成される可能性があります。

元のマイクロパーティションは削除済みとしてマークされていますが、Time TravelとFail-safeを有効にするためにシステムに保持されているため、このプロセスは大量のデータターンオーバーを引き起こす可能性があります。元のマイクロパーティションは、Time Travelの保持期間とそれに続くFail-safe期間の両方が経過した後にのみパージされます(つまり、Snowflake Enterprise以上を使用している場合、延長Time Travelの最小8日から最大97日)。これにより、通常、ストレージコストが増加します。詳細については、 Snowflake Time TravelおよびFail-safe をご参照ください。

重要

テーブルのクラスタリングキーを定義する前に、関連するクレジットとストレージのコストを考慮する必要があります。

再クラスタリングの例

前のトピックの クラスタリング図 に基づいて構築されたこの図は、テーブルの再クラスタリングがクエリのパフォーマンスを向上させるためにマイクロパーティションのスキャンを削減する方法を示しています:

Logical table structures after reclustering
  • 開始するには、テーブル t1 は、当然、マイクロパーティション1-4の date によってクラスタ化されます。

  • クエリ(図内)には、マイクロパーティション1、2、および3のスキャンが必要です。

  • date および type はクラスタリングキーとして定義されます。テーブルが再クラスター化されると、新しいマイクロパーティション(5-8)が作成されます。

  • 再クラスタリング後、同じクエリはマイクロパーティション5および6のみをスキャンします。

さらに、再クラスタリング後:

  • マイクロパーティション5は 一定の状態 (つまり、再クラスタリングでは改善できない)に達しているため、将来のメンテナンスのために深さとオーバーラップを計算するときに除外されます。適切にクラスタ化された大きなテーブルでは、ほとんどのマイクロパーティションがこのカテゴリに分類されます。

  • 元のマイクロパーティション(1-4)は削除済みとしてマークされますが、システムからは 削除されませんTime TravelおよびFail-safe 用に保持されます。

注釈

この例は、非常に小規模な再クラスタリングの影響を示しています。非常に大きなテーブル(つまり、数百万以上のマイクロパーティションで構成される)に外挿すると、再クラスタリングはスキャンに大きな影響を与える可能性があるため、クエリのパフォーマンスに影響を与える可能性があります。

クラスタ化されたテーブルの定義

テーブルのクラスタリング情報の計算

システム関数 SYSTEM$CLUSTERING_INFORMATION を使用して、特定のテーブルのクラスタリングの深さなどのクラスタリングの詳細を計算します。この関数は、テーブルに明示的なクラスタリングキーがあるかどうかに関係なく、任意のテーブルの任意の列で実行できます。

  • テーブルに明示的なクラスタリングキーがある場合、関数はテーブルの名前以外の入力引数を必要としません。

  • テーブルに明示的なクラスタリングキーがない場合(またはテーブルにクラスタリングキーがあるが、テーブル内の他の列の比率を計算する場合)、関数は追加の入力引数として目的の列を取ります。

テーブルのクラスタリングキーの定義

テーブルを作成するときに、 CREATE TABLECLUSTER BY 句を追加することにより、クラスタリングキーを定義できます。

CREATE TABLE <name> ... CLUSTER BY ( <expr1> [ , <expr2> ... ] )

各クラスタリングキーが1つ以上のテーブル列/式で構成されている場合、VARIANT、OBJECT、または ARRAY を 除く 任意のデータ型を使用できます。クラスタリングキーには、次のいずれかを含めることができます。

  • ベース列。

  • ベース列の式。

  • VARIANT 列のパスの式。

例:

-- cluster by base columns
CREATE OR REPLACE TABLE t1 (c1 DATE, c2 STRING, c3 NUMBER) CLUSTER BY (c1, c2);

SHOW TABLES LIKE 't1';

+-------------------------------+------+---------------+-------------+-------+---------+----------------+------+-------+----------+----------------+----------------------+
| created_on                    | name | database_name | schema_name | kind  | comment | cluster_by     | rows | bytes | owner    | retention_time | automatic_clustering |
|-------------------------------+------+---------------+-------------+-------+---------+----------------+------+-------+----------+----------------+----------------------|
| 2019-06-20 12:06:07.517 -0700 | T1   | TESTDB        | PUBLIC      | TABLE |         | LINEAR(C1, C2) |    0 |     0 | SYSADMIN | 1              | ON                   |
+-------------------------------+------+---------------+-------------+-------+---------+----------------+------+-------+----------+----------------+----------------------+

-- cluster by expressions
CREATE OR REPLACE TABLE t2 (c1 timestamp, c2 STRING, c3 NUMBER) CLUSTER BY (TO_DATE(C1), substring(c2, 0, 10));

SHOW TABLES LIKE 't2';

+-------------------------------+------+---------------+-------------+-------+---------+------------------------------------------------+------+-------+----------+----------------+----------------------+
| created_on                    | name | database_name | schema_name | kind  | comment | cluster_by                                     | rows | bytes | owner    | retention_time | automatic_clustering |
|-------------------------------+------+---------------+-------------+-------+---------+------------------------------------------------+------+-------+----------+----------------+----------------------|
| 2019-06-20 12:07:51.307 -0700 | T2   | TESTDB        | PUBLIC      | TABLE |         | LINEAR(CAST(C1 AS DATE), SUBSTRING(C2, 0, 10)) |    0 |     0 | SYSADMIN | 1              | ON                   |
+-------------------------------+------+---------------+-------------+-------+---------+------------------------------------------------+------+-------+----------+----------------+----------------------+

-- cluster by paths in variant columns
CREATE OR REPLACE TABLE T3 (t timestamp, v variant) cluster by (v:"Data":id::number);

SHOW TABLES LIKE 'T3';

+-------------------------------+------+---------------+-------------+-------+---------+-------------------------------------------+------+-------+----------+----------------+----------------------+
| created_on                    | name | database_name | schema_name | kind  | comment | cluster_by                                | rows | bytes | owner    | retention_time | automatic_clustering |
|-------------------------------+------+---------------+-------------+-------+---------+-------------------------------------------+------+-------+----------+----------------+----------------------|
| 2019-06-20 16:30:11.330 -0700 | T3   | TESTDB        | PUBLIC      | TABLE |         | LINEAR(TO_NUMBER(GET_PATH(V, 'Data.id'))) |    0 |     0 | SYSADMIN | 1              | ON                   |
+-------------------------------+------+---------------+-------------+-------+---------+-------------------------------------------+------+-------+----------+----------------+----------------------+

重要な使用上の注意

  • 2つ以上の列/式をテーブルのクラスタリングキーとして定義する場合、順序はデータがマイクロパーティションでどのようにクラスタ化されるかに影響を与えます。

    詳細については、 クラスタリングキーを選択するための戦略 (このトピック)をご参照ください。

  • CREATE TABLE ... CLONE を使用してテーブルを作成すると、既存のクラスタリングキーがコピーされます。

  • CREATE TABLE ... LIKE を使用してテーブルを作成すると、既存のクラスタリングキーは 伝播されません

  • CREATE TABLE ... AS SELECT を使用してテーブルを作成する場合、既存のクラスタリングキーは サポートされません。ただし、テーブルの作成後にクラスタリングキーを定義できます。

  • VARIANT 列の上に直接クラスタリングキーを定義することはサポートされていません。ただし、パスとターゲットタイプで構成される式を指定する場合、クラスタリングキーに VARIANT 列を指定できます。

テーブルのクラスタリングキーの変更

いつでも、 ALTER TABLE を使用して、既存のテーブルにクラスタリングキーを追加したり、テーブルの既存のクラスタリングキーを変更したりできます。

ALTER TABLE <name> CLUSTER BY ( <expr1> [ , <expr2> ... ] )

例:

-- cluster by base columns
ALTER TABLE t1 CLUSTER BY (c1, c3);

SHOW TABLES LIKE 't1';

+-------------------------------+------+---------------+-------------+-------+---------+----------------+------+-------+----------+----------------+----------------------+
| created_on                    | name | database_name | schema_name | kind  | comment | cluster_by     | rows | bytes | owner    | retention_time | automatic_clustering |
|-------------------------------+------+---------------+-------------+-------+---------+----------------+------+-------+----------+----------------+----------------------|
| 2019-06-20 12:06:07.517 -0700 | T1   | TESTDB        | PUBLIC      | TABLE |         | LINEAR(C1, C3) |    0 |     0 | SYSADMIN | 1              | ON                   |
+-------------------------------+------+---------------+-------------+-------+---------+----------------+------+-------+----------+----------------+----------------------+

-- cluster by expressions
ALTER TABLE T2 CLUSTER BY (SUBSTRING(C2, 5, 15), TO_DATE(C1));

SHOW TABLES LIKE 't2';

+-------------------------------+------+---------------+-------------+-------+---------+------------------------------------------------+------+-------+----------+----------------+----------------------+
| created_on                    | name | database_name | schema_name | kind  | comment | cluster_by                                     | rows | bytes | owner    | retention_time | automatic_clustering |
|-------------------------------+------+---------------+-------------+-------+---------+------------------------------------------------+------+-------+----------+----------------+----------------------|
| 2019-06-20 12:07:51.307 -0700 | T2   | TESTDB        | PUBLIC      | TABLE |         | LINEAR(SUBSTRING(C2, 5, 15), CAST(C1 AS DATE)) |    0 |     0 | SYSADMIN | 1              | ON                   |
+-------------------------------+------+---------------+-------------+-------+---------+------------------------------------------------+------+-------+----------+----------------+----------------------+

-- cluster by paths in variant columns
ALTER TABLE T3 CLUSTER BY (v:"Data":name::string, v:"Data":id::number);

SHOW TABLES LIKE 'T3';

+-------------------------------+------+---------------+-------------+-------+---------+------------------------------------------------------------------------------+------+-------+----------+----------------+----------------------+
| created_on                    | name | database_name | schema_name | kind  | comment | cluster_by                                                                   | rows | bytes | owner    | retention_time | automatic_clustering |
|-------------------------------+------+---------------+-------------+-------+---------+------------------------------------------------------------------------------+------+-------+----------+----------------+----------------------|
| 2019-06-20 16:30:11.330 -0700 | T3   | TESTDB        | PUBLIC      | TABLE |         | LINEAR(TO_CHAR(GET_PATH(V, 'Data.name')), TO_NUMBER(GET_PATH(V, 'Data.id'))) |    0 |     0 | SYSADMIN | 1              | ON                   |
+-------------------------------+------+---------------+-------------+-------+---------+------------------------------------------------------------------------------+------+-------+----------+----------------+----------------------+

重要な使用上の注意

  • すでにデータが入力されているテーブルにクラスタリングキーを追加する場合、すべての式をキーに指定できるわけではありません。 SHOW FUNCTIONS を使用して、特定の機能がサポートされているかどうかを確認できます。

    show functions like '関数名';

    出力には、出力の最後に列 valid_for_clustering が含まれます。この列には、データを入力したテーブルのクラスタリングキーで関数を使用できるかどうかが表示されます。

  • テーブルのクラスタリングキーを変更しても、テーブルがSnowflakeによって再クラスタ化されるまで、テーブル内の既存のレコードには影響しません。

テーブルのクラスタリングキーの削除

ALTER TABLE を使用して、いつでもテーブルのクラスタリングキーを削除できます。

ALTER TABLE <name> DROP CLUSTERING KEY

例:

ALTER TABLE t1 DROP CLUSTERING KEY;

SHOW TABLES LIKE 't1';

+-------------------------------+------+---------------+-------------+-------+---------+------------+------+-------+----------+----------------+----------------------+
| created_on                    | name | database_name | schema_name | kind  | comment | cluster_by | rows | bytes | owner    | retention_time | automatic_clustering |
|-------------------------------+------+---------------+-------------+-------+---------+------------+------+-------+----------+----------------+----------------------|
| 2019-06-20 12:06:07.517 -0700 | T1   | TESTDB        | PUBLIC      | TABLE |         |            |    0 |     0 | SYSADMIN | 1              | OFF                  |
+-------------------------------+------+---------------+-------------+-------+---------+------------+------+-------+----------+----------------+----------------------+