インクリメンタルリフレッシュ向けにクエリを最適化する¶
新しい動的テーブルクエリを設計する場合や、既存のクエリをインクリメンタルリフレッシュ用に最適化する場合は、このページを使用します。このガイドでは、パフォーマンスに優れた演算子と、注意が必要な演算子、およびパフォーマンスを向上させるためにクエリを再構築する方法を示します。
インクリメンタルリフレッシュで サポート されるクエリコンストラクトの包括的なリストについては、 動的テーブルでサポートされるクエリ をご参照ください。
演算子ごとのパフォーマンス期待¶
動的テーブルクエリを最適化する前に、どの演算子がインクリメンタルリフレッシュの恩恵を受け、どの演算子が問題を引き起こす可能性があるかを理解してください。
注釈
短いクエリ(10秒未満)では、クエリの最適化やウェアハウスのスケジューリングなどの固定オーバーヘッドにより、パフォーマンスの向上がわずかである可能性があります。
一貫して優れたパフォーマンスを発揮する演算子¶
これらの演算子はインクリメンタルリフレッシュで効率的に機能します。
SELECTWHEREFROM<base table>UNION ALLQUALIFY[RANK|ROW_NUMBER|DENSE_RANK] ... = 1
Snowflakeが各演算子を処理する方法の詳細については、 演算子リファレンステーブル をご参照ください。
データの局所性の影響を受ける演算子¶
これらの演算子の場合、パフォーマンスはデータの整理方法と、キーに関連して変更が発生する データの局所性 に依存します。
INNER JOINOUTER JOINGROUP BYDISTINCTOVER(ウィンドウ関数)
変更が、グループ化キーまたはパーティションキーのごく一部にのみ影響する場合、これらの演算子は正常に実行されます。データの局所性がウェアハウスよりも優先的である場合や、多くのキーに変更が分散している場合は、インクリメンタルリフレッシュがフルリフレッシュよりも 遅く なることがあります。
Snowflakeが各演算子を処理する方法の詳細については、 演算子リファレンステーブル をご参照ください。
一般的な最適化パターン¶
次のセクションでは、局所性の影響を受ける演算子を使用するクエリを最適化するための一般的なパターンを示します。
集計を最適化する¶
GROUP BY を使用する場合、Snowflakeは、変更を含むすべてのグループ化キーの集計を再計算します。パフォーマンスは次の要因に依存します。
データクラスタリング :グループ化キーによってクラスター化されたソースデータは最高のパフォーマンスを発揮します。
変更の分布 :グループ化キーの5%未満に影響する変更をターゲットにしています。
キーの複雑さ :単純な列参照は、複合式よりもパフォーマンスが高くなります。
問題:グループ化キーでの複合式の簡略化¶
このクエリは、グループ化キーが式であるため、パフォーマンスが低下します。
CREATE DYNAMIC TABLE hourly_sums
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT DATE_TRUNC('minute', ts), SUM(amount)
FROM transactions
GROUP BY 1;
解決策:式をマテリアライズする¶
2つの動的テーブルに分割して、単純なグループ化キーを公開します。
CREATE DYNAMIC TABLE transactions_with_minute
TARGET_LAG = DOWNSTREAM
WAREHOUSE = my_warehouse
AS
SELECT DATE_TRUNC('minute', ts) AS ts_minute, amount
FROM transactions;
CREATE DYNAMIC TABLE hourly_sums
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT ts_minute, SUM(amount)
FROM transactions_with_minute
GROUP BY 1;
ここで、 GROUP BY は単純な列で動作し、中間テーブルはより良い データの局所性 の利点を活用できます。
結合の最適化¶
結合のパフォーマンスは、どちらの側で変更され、どのようにデータをクラスタリングするかに依存します。
INNER JOIN :Snowflakeは左側からの変更を右側のテーブルと結合し、右側からの変更を左側のテーブルと結合します。結合は、片側が小さい場合や変更がまれな場合に良好に機能します。
OUTER JOIN :Snowflakeはまた、 一致しない行について、NULL値を計算する必要もあります。どちら側の変更かがパフォーマンスに大きな影響を与えます。
問題:クラスタリングが不十分な両側の大きなテーブル¶
どちらのソーステーブルも結合キーによってクラスター化されていません。
CREATE DYNAMIC TABLE order_details
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT o.order_id, o.customer_id, p.product_name, o.quantity
FROM orders o
JOIN products p ON o.product_id = p.product_id;
解決策:変更頻度の低いテーブルをクラスター化する¶
ディメンジョンテーブルを結合キーでクラスタリングします。そして、結合はより良い局所性の恩恵を受けます。
ALTER TABLE products CLUSTER BY (product_id);
CREATE DYNAMIC TABLE order_details
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT o.order_id, o.customer_id, p.product_name, o.quantity
FROM orders o
JOIN products p ON o.product_id = p.product_id;
OUTER JOINsの場合:
LEFT側に、より頻繁に変更されるテーブルを配置します。
OUTERキーワードの反対側の変更を最小限に抑えるようにします。
FULL OUTER JOINsの場合、、優れた局所性は両側とも重要です。
ウィンドウ関数の最適化¶
Snowflakeは、変更を含むすべてのパーティションキーで ウィンドウ関数 の再計算を行います。GROUP BY と同様に最適化します。
主な要件:
常にPARTITION BY句を含めます。PARTITION BYのないウィンドウ関数は、完全な再計算が行われます。
パーティションキーによるソースデータのクラスタリング。
パーティションの5%未満への変更を保持します。
問題:パーティションクラスタリングのないウィンドウ関数¶
ソーステーブルはパーティションキーによってクラスター化されていません。
CREATE DYNAMIC TABLE ranked_sales
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT
region,
salesperson,
amount,
RANK() OVER (PARTITION BY region ORDER BY amount DESC) as sales_rank
FROM daily_sales;
解決策:パーティションキーによるクラスター¶
ウィンドウ関数が局所性を利用するように、パーティションキーでソーステーブルをクラスター化します。
ALTER TABLE daily_sales CLUSTER BY (region);
CREATE DYNAMIC TABLE ranked_sales
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT
region,
salesperson,
amount,
RANK() OVER (PARTITION BY region ORDER BY amount DESC) as sales_rank
FROM daily_sales;
効率的に重複を削除(DISTINCTとQUALIFYの比較)¶
DISTINCT および QUALIFY はどちらも重複を削除できますが、パフォーマンスは異なります。
DISTINCT:GROUP BY ALL と同等です。局所性はパフォーマンスに直接影響します。局所性が悪いとリフレッシュが遅くなります。
QUALIFY と ROW_NUMBER = 1 :Snowflakeは、パターン QUALIFY ROW_NUMBER() ... = 1 が動的テーブルの最上位に投影されている場合は最適化します。このパターンは、一貫してフルリフレッシュよりも高速に実行されます。
最適化は、OVER()句のすべてのPARTITION BYおよびORDER BYキーが動的テーブルで永続化されている(トップレベルの射影に含まれている)ときに最もうまく機能します。
推奨事項:可能な場合はDISTINCTのではなくQUALIFYを使用する¶
次の例では、 DISTINCT を使用します。
CREATE DYNAMIC TABLE unique_customers
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT DISTINCT customer_id, customer_name, email
FROM customer_events;
次の例では、 QUALIFY を使用します。
CREATE DYNAMIC TABLE unique_customers
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT customer_id, customer_name, email, event_time
FROM customer_events
QUALIFY ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY event_time DESC) = 1;
QUALIFYのバージョンは、どの重複(最新)を保持するかについてより明示的であり、一貫したパフォーマンスを発揮します。
冗長なDISTINCT操作を削除する¶
それぞれのDISTINCTはリフレッシュのたびにリソースを消費します。データがすでに一意である場合や、上流での重複排除の場合は、不要なDISTINCT句を削除します。
演算子リファレンス¶
次のテーブルは、Snowflakeがインクリメンタルリフレッシュ中に各SQL演算子を処理する方法を説明しています。
演算子 |
Snowflakeが処理する方法 |
パフォーマンスのメモ |
|---|---|---|
SELECT |
変更された行にのみ式を適用します。 |
パフォーマンスは良好です。特に考慮事項はありません。 |
WHERE |
変更された行に対してのみ述語を評価します。 |
パフォーマンスは良好です。コストは変更に応じて線形に変化します。注意:非常に選択的なWHEREは、出力が変わらなくてもウェアハウスのアップタイムが必要になることがあります。 |
FROM <table> |
前回のリフレッシュ以降にSnowflakeが追加または削除したマイクロパーティションをスキャンします。 |
コストは、変更されたパーティションの量に応じて変化します。ソーステーブルの約5%に変更を制限します。 |
UNION ALL |
各サイドからの変更の結合を取得します。 |
パフォーマンスは良好です。特に考慮事項はありません。 |
WITH (CTEs) |
各共通テーブル式の変更を計算します。 |
良好なパフォーマンスになりますが、単一テーブルの定義が非常に複雑になることは避けてください。複数の動的テーブルに分割することを検討してください。 |
スカラー集計 |
入力が変更された場合、集計を完全に再計算します。 |
パフォーマンスを重視するテーブルでは避けます。代わりに定数でグループ化することを検討してください。 |
GROUP BY |
変更されたグループ化キーの集計を再計算します。 |
グループ化キーにってソースをクラスタリングします。キーには複合式は避けます。集計を最適化する をご参照ください。 |
DISTINCT |
GROUP BY ALLと同等です。 |
局所性の影響を受けます。代わりにQUALIFYの使用を検討してください。効率的に重複を削除(DISTINCTとQUALIFYの比較) をご参照ください。 |
ウィンドウ関数 |
変更されたパーティションキーの再計算。 |
常にPARTITION BYを含めます。パーティションキーによってソースをクラスター化します。ウィンドウ関数の最適化 をご参照ください。 |
INNER JOIN |
テーブルの両側からの変更を結合します。 |
片側が小さい場合に良好なパフォーマンスになります。変更頻度の低い側をクラスター化します。結合の最適化 をご参照ください。 |
OUTER JOIN |
NULL計算について、内部結合をNOT EXISTSクエリと組み合わせます。 |
最も局所性の影響を受ける演算子です。結合の最適化 をご参照ください。 |
LATERAL FLATTEN |
変更された行にのみフラット化を適用します。 |
パフォーマンスは良好です。コストは変更に応じて線形に変化します。 |
ランキング付きQUALIFY |
ROW_NUMBER/RANK/DENSE_RANK ... = 1に対して最適化されたパスを使用します。 |
高効率です。動的テーブルの最上位の投影にQUALIFYを配置します。 |