dbtのtestを介してSnowflakeの各制約を自動的に適用できるpackage「dbt_constraints」を試してみた #dbt #SnowflakeDB
さがらです。
dbtのtestを介してSnowflakeの各制約を自動的に適用できるpackage、「dbt_constraints」を試してみたので本記事でその内容をまとめてみます。
dbt_constraintsとは
dbt_constraintsに関する情報は、下記ページにまとまっております。
このページの説明を見ると、
This package generates database constraints based on the tests in a dbt project. It is currently compatible with Snowflake, PostgreSQL, and Oracle only.
(DeepL翻訳) 本パッケージは、dbtプロジェクト内のテストに基づいてデータベース制約を生成します。現在、Snowflake、PostgreSQL、Oracleのみと互換性があります。
…ということで、dbtのtestの内容に応じて各制約を自動で生成し適用してくれるpackageとなっております。
改めて、Snowflakeでは以下の4種類の制約をサポートしています。(Snowflakeの制約に関する公式Docはこちら)
UNIQUE
PRIMARY KEY
FOREIGN KEY
NOT NULL
一方で、dbtのGeneric testsは以下の4種類となっております。(dbtのGeneric testsに関する公式Docはこちら)
unique
:UNIQUE
制約に該当するテストnot_null
:NOT NULL
制約に該当するテストaccepted_values
:該当する制約なしrelationships
:FOREIGN KEY
制約に該当するテスト
こう見ると、「PRIMARY KEY
制約はどうやって適用するの…?」となってしまいますが、実はdbt_constraintsは、dbt_constraints.primary_key
、dbt_constraints.unique_key
、dbt_constraints.foreign_key
という3種類のテストも提供してくれています!そのため、PRIMARY KEY
制約はdbt_constraints.primary_key
テストを定義すればOKです。
詳細は後述しますが、dbtに元々備わっているデフォルトのGeneric testsを用いても、dbt_constraintsに含まれるテストを用いても、各制約を自動的に適用することが出来るのです。既存のGeneric testsの記述を書き換えなくても良いのが便利ですね!
Snowflakeで制約を適用するメリット
ただ、Snowflakeの制約と聞いて、「Snowflakeの制約って、NOT NULL
制約以外強制しないから意味ないんじゃないの?」と思ってしまう方もいるかもしれませんが、そんなことはありません!
例えば、こちらのドキュメントにある「RELY制約プロパティ」を設定すると、クエリの内容から必要最低限のテーブルJOINを行うように処理を最適化してくれます。
下記は私が以前試した内容ですが、関係するテーブルをすべてJOINしたView(俗に大福帳ともいう)をTableauから参照したとき、選択したフィールドに応じて必要最低限のテーブルだけがJOINされることを確認しています。
また、BIツール上でJOINを定義するときFOREIGN KEY
制約に関するメタデータをSnowflakeから抽出し、JOINを行うときに結合キーを自動で適用してくれることもあります。(詳細はこちらの公式Docを。)
そのため、Snowflakeの通常のテーブルであっても制約を適用するメリットはあると私は考えています。
注意点:本packageの運用保守について
こちらのdbt_constraintsについて、リポジトリはSnowflake Labs上にあるため一見Snowflake社公式が管理しているdbt packageと思ってしまいそうですが、このdbt packageはSnowflake社のSenior Solutions ArchitectであるDan Flippo氏を中心にコミュニティを介して開発されたものです。
そのため、何かしら予期せぬエラーが発生したり機能要望をしたい場合は、直接下記のGitHubのリポジトリに対してIssueを立てましょう!
試してみた
jaffle_shop_metricsのリポジトリをforkして、すべてのmodelからtableが生成されるようにdbt_project.yml
を変更した上で、試していきます。(当たり前ですが、Viewに対しては制約をかけることが出来ないためです。)
dbt_constraintsのインストール
まず、dbt_constraintsを対象のdbtプロジェクトに対してインストールします。
dbt_project.yml
と同じ階層に、packages.yml
を定義し、以下の内容を記述します。すでにpackages.yml
がある場合は、下記の内容の- package:
以降を追記してください。(dbt_constraintsの最新バージョンは、都度公式から確認するようにしてください。)
記述を終えてファイルを保存したら、dbt deps
コマンドでインストールしましょう。
packages: - package: Snowflake-Labs/dbt_constraints version: [">=0.6.0", "<0.7.0"]
dbt_constraintsのテストを用いて制約を適用
まず、dbt_constraintsに含まれるテストを用いて制約を適用してみます。
jaffle_shop_metricsのstg_orders.yml
の中身を以下に書き換えてみます。
dbt_constraints.primary_key
は対象のカラムがPRIMARY KEYであるかを確認するテスト、dbt_constraints.foreign_key
は対象のカラムの値がすべて指定したモデルのフィールドに存在しているか(FOREIGN KEYであるか)を確認するテストです。
version: 2 models: - name: stg_orders columns: - name: order_id tests: - dbt_constraints.primary_key - name: customer_id tests: - dbt_constraints.foreign_key: to: ref('stg_customers') field: customer_id
この上で一度dbt build
コマンドを実行し、オブジェクト生成とテストを行います。
コマンド実行後にSnowflake上でstg_orders
テーブルを確認すると、order_id
カラムにはPRIMARY KEY
制約と必要条件であるNOT NULL
制約、customer_id
カラムにはFOREIGN KEY
制約、が適用されていました!
ちなみに、dbtで生成されるドキュメントからorder_id
カラムについて見てみると、Custom Test
の記載があり展開すると、dbt_constraints.primary_key
でテストされていることがわかるようになっていました。
dbtデフォルトのGeneric testsから制約を適用
続いてdbtデフォルトのGeneric Testを用いて、自動的に制約が適用されるか確認してみます。
jaffle_shop_metricsのstg_orders.yml
の中身を以下に書き換えて、unique
、not_null
、relationships
のテストが行われるようにします。
※PRIMARY KEY
制約を追加したい場合は、dbt_constraints.primary_key
でテストする必要があるためご注意ください。
version: 2 models: - name: stg_orders columns: - name: order_id tests: - unique - not_null - relationships: to: ref('stg_customers') field: customer_id
この上で一度dbt build
コマンドを実行し、オブジェクト生成とテストを行います。
コマンド実行後にSnowflake上でstg_orders
テーブルを確認すると、UNIQUE
制約、FOREIGN KEY
制約、NOT NULL
制約、が適用されていました!
これで既存のGeneric testsを書き換えなくても問題ないことが確認できました。強いて言えば、PRIMARY KEY
制約はdbt_constraintsのdbt_constraints.primary_key
テストを使う必要があるので、ここだけ注意ですね。
最後に
dbtのtestを介してSnowflakeの各制約を自動的に適用できるpackage「dbt_constraints」を試してみました。
本packageを用いてテストを定義するだけで、各制約とRELY制約プロパティを適用でき、クエリのJOIN処理の最適化を図ることができます。積極的に使っていきましょう!