💡

【dbt Docs】Guides - Best practices

2022/03/23に公開

Best practices

https://docs.getdbt.com/docs/guides/best-practices

https://zenn.dev/tenajima/articles/dbt_best_practice

dbtの経験豊富なユーザーによる、分析業務における最適な使用方法についての知恵を集めています。
これらのベストプラクティスを守ることで、あなたの分析チームが可能な限り効果的に作業できるようになり、また、これらのプロヒントを実行することで、あなたのdbtプロジェクトに磨きがかかるでしょう

Best practice workflows

Version control your dbt project

(dbtプロジェクトはバージョン管理する)
dbtプロジェクトは、すべてバージョン管理する。新機能の開発やBugfixをするために、Gitのブランチを切って行う。すべてのコードの変更は、プルリクエストを出し、コードレビューをしてもらって、 mainにマージする。

Use separate development and production environments

** 開発環境と本番環境をしっかり分ける**
dbtでは、profileのtargetの機能を使って、簡単に本番環境と開発環境を分けて整備することが簡単。
devでは、ローカルでコマンドラインを実行する。
prodでは、本番環境でのみ動かす

Use a style guide and for your project

開発スタイルをしっかり定める。SQLの書き方とか、カラムの名前つけ方針とか。
下記を参考にする

https://github.com/dbt-labs/corp/blob/master/dbt_style_guide.md

Best practices in dbt projects

Use the ref function

常にref関数を使う
ref関数を使うことで依存関係が取得、モデル構築の実行順などもできる。

Limit references to raw data

source関数を使う。

Rename and recast fields once

生データは一般に、ソースに準拠した構造、つまりソースが定義するスキーマや命名規則に従って保存されます。この構造はソースごとに異なるだけでなく、分析に使用したい命名規則とも異なる可能性があります。

dbtプロジェクトの最初のレイヤーのトランスフォームを行う必要があります。

  • 1つのsourceからのみselect
  • プロジェクトの命名規則などに合わせて、テーブル名やカラム名を変更する。
  • フィールドを正しいデータ型に再キャストする。例えば、日付をUTCに、価格をドルに変更する。

それ以降のデータモデルは、これらのモデルの上に構築することで、重複するコードの量を減らすことができます。

Break complex models up into smaller pieces

複雑なモデルを分割して小さくする Simple is Best!!

複雑なモデルは、CTEs(WITH句的なやつ)が複数あったりする。dbtにおいては、CTEを複数のモデルに分割して、その上で構築することができ、シンプルで見通しを良くすることができる。

  • CTEが2つのモデルで重複している。CTEを別のモデルに分割することで、下流の任意の数のモデルからそのモデルを参照することができ、重複するコードを減らすことができます。
  • CTEは、選択するデータの粒度を変更します。データの粒度(1つのレコードが表すもの)を変更するような変換をテストすることは、しばしば有用である。CTEを別のモデルに分割することで、より大きなモデルから独立してこの変換をテストすることができます。
  • クエリのSQLは何行にもわたる。CTEを個別のモデルに分割することで、他のdbtユーザ(または未来の自分)がコードを見るときの認知負荷を軽減することができます。

Group your models in directories

models/のしたには複数のサブディレクトリを作ることができる。なので、それでより整理して把握しやすいように

  • dbt_project.ymlでモデルのグループが指定できる。
  • DAGの一部のみを実行することもできる
  • モデリングの手順を共有
  • 例えば、「martsディレクトリのモデルは、martsディレクトリの他のモデル、またはstagingディレクトリのモデルからしか選択できない」というように、モデルの上流依存関係を許容する規約を作成します。

Add tests to your models

dbtはテストのフレームワークを提供する

  • SQLが期待通りの変換をしている
  • データソースが期待通りのデータを持っている

Consider the information architecture of your data warehouse

(使っているDWHの情報アーキテクチャを考慮する)

SQLクライアントでデータウェアハウスに接続した場合、ユーザーはスキーマ、リレーション、カラムの名前を頼りに、表示されるデータを理解することがよくあります。データウェアハウスの情報アーキテクチャを改善するために以下のことをする

  • カスタムスキーマを使用して、リレーションを論理的なグループ分けにしたり、中間モデルを別のスキーマに隠したりする。一般的に、これらのカスタムスキーマはモデルをグループ化するために使用するディレクトリと一致し、dbt_project.ymlファイルで設定できる。
  • テーブル名の接頭辞(例えば、stg_fct_dim_)を使用して、エンドユーザーが照会すべきリレーションシップを示すことができます。

Choose your materializations wisely

(マテリアライズを賢く使う)
Materialization(実体化?)は、モデルをどう実現するかであり、一般的なルールとしては

  • viewは構築は早い、しかしtableに比べてクエリ性能は低い
  • Incrementalモデルは、tableと同等のクエリ性能を持ち、テーブルのマテリアライゼーションと比較して、より速く構築できる。。しかし、プロジェクトが複雑になってしまう。

なのでどのマテリアライゼーションを選ぶかは

  • デフォルトでは、view
  • ephemeralモデルは、簡単な変形(名前変えたり、桁合わせしたりする程度)にのみ使って、ユーザに公開するロコろでは使わない
  • BIツールが使うところは、Tableにする
  • 複数の子孫を持つモデルにはtableを使用する
  • テーブルモデルのビルド時間が許容閾値を超えた場合、インクリメンタルモデルを使用する

Pro-tips for workflows(より上級のTips)

Use the model selection syntax when running locally

( モデルの選択(たぶん、--select)は、ローカルで動かす時に使う)
開発中は、開発しているモデルとその下位モデル(=ダウンストリームモデル、依存関係的に下流)のみを実行するのが良い。モデルの選択オプションを使って、実行するモデルを選択するのが良き

Run only modified models to test changes ("slim CI")

(変更したモデルのみ実行し、変更をテストする)
新規開発や変更をプロジェクトに安心してマージするためには、その変更によってプロジェクトの他の部分が壊れないか?を確認することが寛容。
そのために、モデルの実行とテストはサンドボックス環境でおこない、本番データとは隔離した環境で行う。そして、Gitのワークフローで自動的にチェックが行われるように設定する。
参考:https://docs.getdbt.com/docs/dbt-cloud/using-dbt-cloud/cloud-enabling-continuous-integration

同時に、プロジェクト内のすべてのモデルを実行し、テストするためには時間(とお金)がかかります。この非効率性は、PRがほんの一握りのモデルへの変更しか提案しない場合、特に苦痛に感じられます。

dbtは、前回の生産時の成果物と比較することで、どのモデルが変更されているかを判断し、変更されていない親モデルの上に構築することができます。

dbt run -s state:modified+ --defer --state path/to/prod/artifacts
dbt test -s state:modified+

dbtは、以前の生産ランの成果物と比較することで、モデルやテスト結果のステータスを判断することができます。

  • result:fail
  • result:error
  • result:warn
  • result:success
  • result:skipped
  • result:pass

よりスマートなRerunの方法は、result:<status>を使うこと。

dbt run --select state:modified+ result:error+ --defer --state path/to/prod/artifacts
  • 誤ったモデルをすべて再実行し、同時に行った、誤ったモデルに関連する可能性のある変更も実行し、下流で使用する。
dbt build --select state:modified+ result:error+ --defer --state path/to/prod/artifacts
  • 誤ったモデルをすべて再実行し、再テストする。また、誤ったモデルに関連する可能性のある変更を同時に実行し、下流で使用する。
dbt build --select state:modified+ result:error+ result:fail+ --defer --state path/to/prod/artifacts
  • 誤ったモデルや失敗したテストをすべて再実行する。
  • 誤ったモデルをすべて再実行し、同時に行った、誤ったモデルに関連する可能性のある変更も実行し、下流で使用する。
  • 変更されたノードやエラーノードとは無関係のテストが失敗している(合格するためにデータロードをリフレッシュする必要があるソーステストと考える)。
dbt test --select result:fail --exclude <example test> --defer --state path/to/prod/artifacts
  • 失敗したテストをすべて再実行し、それでも失敗することが分かっているテストを除外する。
  • これは、"EL "処理中のソースデータの更新が、リフレッシュされた後に再実行される必要がある場合に適用できる

Pro-tips for dbt Projects

Limit the data processed when in development

(開発するときは、データ量を制限して実行する)
開発環境では、実行時間が速ければ速いほど、より速くコードを反復することができます。私たちは、ターゲット名に基づいてデータを制限するパターンを使用することで、頻繁に実行を高速化させています。

select
*
from event_tracking.events
{% if target.name == 'dev' %}
where created_at >= dateadd('day', -3, current_date)
{% endif %}

Use hooks to manage privileges on objects that dbt creates

hookを使って、dbtで生成されるオブジェクトの権限を管理する)

  • dbtでオブジェクトを作る時に、hookをもちいて、パーミッションを設定する。
  • これを設定することで、バージョン管理的にも常に同じパーミッションを設定できる(保証できる)

参考
https://discourse.getdbt.com/t/the-exact-grant-statements-we-use-in-a-dbt-project/430

Separate source-centric and business-centric transformations

(データソース層とビジネス層のへ変換を分離する)

データをモデリングするに当たり、下記の2つのステップがよくある

  • 異なるソースからのデータを一貫性のある構造に変換するソースセントリック変換,カラムのエイリアシングやリキャスト、ソースデータの結合や重複排除により、モデルに正しい粒度を持たせることができます。
  • ビジネスに関連するエンティティやプロセスを表すモデルにデータを変換したり、SQLでビジネス定義を実装するビジネスセントリックな変換を行います。

ソース中心、ビジネス中心のロジックの区別を明確にするために、この2種類の変換を別のモデルに分けることが最も有効であると考えます。

Managing whitespace generated by Jinja

(Jinjaが生成するホワイトスペースの管理 ??)
モデルでマクロやJinjaの他の部分を使用している場合、コンパイルされたSQL(target/compiledディレクトリにあります)には不要な空白が含まれている可能性があります。生成される空白を制御する方法については、Jinja のドキュメントをチェックしてください。

Discussion