Snowflakeでworkloadごとに異なるウェアハウスサイズを使い分けることは、パフォーマンスとコスト最適化の両面で大きな効果を発揮します。dbtはSnowflakeとネイティブに連携しており、モデル単位で使用するウェアハウスを指定できます。本記事では、その具体的な使い方とベストプラクティスを解説します。なぜウェアハウスサイズを変更するのか?
dbtプロジェクトの実行に時間がかかるようになり、SLA未達やユーザー体験の悪化につながっている場合、ウェアハウスサイズを上げることで処理速度を改善できる可能性があります。すでにdbtのデフォルトウェアハウスサイズを大きくしている場合は、効果のあるモデルだけサイズを上げることでコストを抑える余地もあります。
dbtモデルを高速化する
データ量が増えるにつれて、モデルの実行時間は徐々に長くなりがちです。データ量に比例して直線的に遅くなるモデルもあれば、集計関数やJOINを多用するモデルのように、データ量の増加に対して計算負荷が指数関数的に膨らむケースもあります。特にモデルがリモートストレージへのスピルを起こすと、実行時間への影響は一段と大きくなります(詳しくはクエリプロファイルに関する記事をご覧ください)。
クエリを高速化する最も効果的な方法は、処理するデータ量そのものを減らすことです。テーブルマテリアライゼーションを使っているモデルが遅くなってきたら、インクリメンタルマテリアライゼーションに切り替えて、新規または更新分のデータだけを処理する構成を検討しましょう。
すでにインクリメンタル化を行っている場合や、そもそも適用が難しい場合は、次の手としてウェアハウスサイズを上げるのが有効です。
dbtのデフォルトSnowflakeウェアハウスを設定する
dbtはデフォルトで、プロジェクトのprofiles.ymlに指定されたSnowflakeウェアハウスを使用します。指定がない場合は、dbtのSnowflakeユーザーに紐づくデフォルトウェアハウスが使われます。このウェアハウスを別の大きなものに切り替えるか、既存ウェアハウスのサイズ自体を変更すれば、dbtはすべてのクエリを大きなウェアハウスで実行するようになります。dbtの実行環境に応じて、ウェアハウスはprofiles.ymlファイル、またはdbt Cloudの環境レベルで変更します。
profiles.yml
profiles.ymlファイルで、warehouseの設定を別の仮想ウェアハウスに書き換えます。各ウェアハウスのサイズはSnowflake側で設定します。
select_internal:
outputs:
dev:
type: snowflake
account: org.account
user: niall
password: XXXXX
warehouse: dev
database: dev
schema: niall
threads: 8
target: dev
dbt Cloud
dbt Cloudでは、上部メニューの Deploy > Environments を開きます。編集したい環境を選び、Settings をクリック。Edit を押して Deployment Connection までスクロールすると、ウェアハウスを変更できます。ウェアハウスのサイズはSnowflake側で設定します。
ただし、dbtのデフォルトウェアハウスサイズを上げるのは必ずしも得策ではありません。プロジェクト内の大半のクエリはサイズアップの恩恵を受けず、結果的にSnowflakeのコストだけが膨らむ恐れがあります。ウェアハウスサイズがクエリ速度に与える影響については、ウェアハウスサイジングに関する記事をご覧ください。デフォルトサイズを上げるよりも、デフォルトはX-Smallに設定し、必要に応じてモデル単位で上書きすることをおすすめします。
dbtモデル単位でSnowflakeウェアハウスサイズを設定する
モデル単位でウェアハウスを指定すれば、それぞれのモデルの要件に合わせたサイズを選択でき、パフォーマンスとコストの両方を最適化できます。
ウェアハウスをハードコーディングする
dbtにはsnowflake_warehouseというモデル設定が用意されています。個別のモデルで指定する場合は次のように書きます。
{{ config(
snowflake_warehouse="dbt_large"
) }}
select
...
from {{ ref('stg_orders') }}
dbt_project.ymlを使えば、ディレクトリ配下のすべてのモデルに一括で適用することもできます。
name: my_project
version: 1.0.0
---
models:
+snowflake_warehouse: 'dbt_xsmall'
my_project:
clickstream:
+snowflake_warehouse: 'dbt_large'
環境に応じて動的にウェアハウス名を切り替える
本番環境で使いたいウェアハウスと、開発・CI・自動テストで使いたいウェアハウスは異なるケースがほとんどです。モデル単位で指定するウェアハウスについても同じことが言えます。これを実現するには、先ほどの直書きの値の代わりにマクロを使います。
{{ config(
snowflake_warehouse=get_warehouse('large')
) }}
select
...
from {{ ref('stg_orders') }}
このマクロには、環境ごとに使用するウェアハウスサイズを返すロジックを実装できます。
例えば、本番環境ではdbt_production_<size>(dbt_production_xsmall、dbt_production_small、dbt_production_mediumなど)、CI環境ではdbt_ci_<size>という命名のウェアハウスを作成しているとします。ローカル開発ではデフォルトのウェアハウスを使い、指定されたサイズは無視したい。さらに、許可リストにないサイズが指定された場合はエラーを出したい。こうした要件は、次のようなマクロで実現できます。
{% macro get_warehouse(size) %}
{% set available_sizes = ['xsmall', 'small', 'medium', 'large', 'xlarge', '2xlarge'] %}
{% if size not in available_sizes %}
{{ exceptions.raise_compiler_error("Warehouse size not one of " ~ valid_warehouse_sizes) }}
{% endif %}
{% if target.name in ('production', 'prod') %}
{% do return('dbt_production_' ~ size) %}
{% elif target.name in ('ci') %}
{% do return('dbt_ci_' ~ size) %}
{% else %}
{% do return(None) %}
{% endif %}
{% endmacro %}
なお、snowflake_warehouseの設定でマクロを使えるのはモデルファイル内に限られ、dbt_project.ymlでは使用できません。
dbtのその他のリソースに対するウェアハウス設定
現時点でウェアハウスを設定できるのは、モデルとスナップショットのみです。テストなど他のリソースへの対応状況を追いたい方は、こちらのGitHub Issueをチェックしてみてください。
dbtモデルのパフォーマンスとコストをモニタリングする
ぜひdbt_snowflake_monitoring dbtパッケージもご活用ください。使いやすいdbt_queriesモデルを提供しており、dbtモデルのパフォーマンスを時系列で把握できます。コストを個々のモデル実行に紐づけて算出できるため、「過去1か月で最もコストのかかったモデル トップ10は?」といった問いにもすぐ答えを出せます。
お読みいただきありがとうございました。次回は、Snowflake上でのdbtパフォーマンス最適化について、さらに踏み込んだ推奨事項をご紹介します。最新記事の通知を受け取りたい方はぜひご購読ください。ご質問があればお気軽にお問い合わせください。
Niall Woodward・SELECT 共同創業者兼CTO
NiallはSaaS型のSnowflakeコスト管理・最適化プラットフォームであるSELECTの共同創業者兼CTOです。SELECTを立ち上げる前は、Brooklyn Data Companyや複数のスタートアップでデータエンジニアを務めていました。オープンソースの愛好家でもあり、SQLFluffのメンテナーを務めるほか、dbt_artifacts、dbt_snowflake_monitoring、dbt_query_tagsという3つのdbtパッケージの作者でもあります。