[dbt] custom schemaを使って普段とは別のスキーマ下にデータモデルを作成する

ノーマルにはノーマルのカッコよさってもんがあるんです
2021.08.23

大阪オフィスの玉井です。

今回は下記の機能を使ってみたので、ご紹介します。

dbtはどこにデータモデルを作るのか?

dbtはELTの「T」を担当するツールということで、分析に最適化されたテーブルやビューを簡単に構築することができる…というのは、dbtを調べたり触ったりしたことがある方はわかると思います。

では、その「分析に最適化されたテーブルやビュー」というのは、どのDB・どのスキーマに作られるのでしょうか。

ざっくりいうと最初の設定で指定した場所に作られる

DBについては、Projectを作成するときに、対象のDWHの接続情報を設定しますが、そのときに指定した場所になります。ついでに、スキーマも合わせて設定できますが、こちらは接続情報として設定するのではなく、ユーザー毎に持つ「開発用の資格情報」として設定します。

「なんでこの設定こんな分かれ方してんの?」って思っちゃいますが、「どのスキーマに作るか?」をユーザー毎に設定することによって、1つのDB下に開発ユーザーの分だけ開発用スキーマを用意することができます。これにより、開発者は自分専用のスキーマ下に(他との干渉を気にせず)データモデルを実際に構築することができます。普通のシステム開発でいうローカル環境みたいなものを、DWH上に用意するイメージですね(いわゆるビッグデータを扱う場合、ローカル環境オンリーでは到底検証できないため、開発中のDWHが使用できるメリットは大きいです)。

基本、Project内で指定できるスキーマは1つ

(1ユーザーにとっての)開発環境・及び本番環境において、各データモデルを作成するときに指定できるスキーマは、基本的に1つです。10個のデータモデルを作成したとして、そのデータモデルは全て(設定した)1つのスキーマ下に作成されます。

「それじゃ困る。このデータモデルは別のスキーマに格納したい」。そんなときに使うと助かるかもしれないのが、今回取り上げるcustom schemaになります。

やってみた

環境

  • dbt Cloud
    • 実行する時のJobのバージョンは0.19.1
  • Snowflake 5.31.4

custom schemaを使わない場合

dbt側でこういう感じにモデルを作っているとします。

これを実行すると、DWH側ではこうなります。

フォルダ分けとか関係なく、DBT_SANDBOXというスキーマ下にずら〜っと作られます。

custom schemaを使ってみる

今回は「tpch_2というフォルダ下にあるモデルだけ別スキーマにしたい」をやってみます。

モデル毎に(構築先のスキーマを)指定する方法もありますが、今回はdbt_project.ymlでまとめて指定します。

下記のように、modelsの部分で、+schemaで構築先のスキーマを指定することができます。ちなみに、事前に作っておく必要はありません(dbt側が作ってくれます)。

dbt_project.yml

models:
  tpch_project:
      tpch:
          materialized: table
      tpch_2:
          +schema: another_schema

この状態で実行すると、下記のようにスキーマが別途作成されます。

custom schemaで作成されたスキーマの名前について

上記の画像を見て「あれ?」と思った方もいるのではないでしょうか。スキーマの名前がDBT_SANDBOX_ANOTHER_SCHEMAとなっていますね。YAMLファイルで記述したのはanother_schemaなのに。

これはdbtの仕様によるものです。dbtのcustom schemaは「元々設定してたスキーマ名」+「custom schemaで指定した名前」という命名規則になっています。

上記のようになっている理由はドキュメント(当記事冒頭参照)に書いてありますが、ここでもざっくり説明します。もし、こういう仕様ではなかった場合(記述した名前がそのまま使われた場合)…

  • (前述したように)ユーザー毎にスキーマを持つ方法が想定されているため、開発ユーザーの数だけ、同名スキーマが乱立してしまう
  • 本番環境にも開発と同名のスキーマができてしまう

上記のようなリスクを避けるため、dbtのcustom schemaは、なるべく同名を出さないようになっています。

命名ロジックを任意のものに変える

とはいえ、色々な事情があって、命名ロジックをカスタマイズしたいときもあると思います。大丈夫です。可能です。

実は、custom schemaの命名ロジックはマクロで書かれています(中身も公式ドキュメントにあります)。このマクロをユーザー側で作ったもので上書きすると、そちらのロジックが使用されます

上書きといっても、手順は非常に簡単で、Macroフォルダ下にget_custom_schema.sqlを作れば、dbtはcustom schemaを実行する時、命名ロジックの参照先をこちらに切り替えます。

試しに、命名の順序を入れ替えたものを設定してみます。

get_custom_schema.sql

{% macro generate_schema_name(custom_schema_name, node) -%}

    {%- set default_schema = target.schema -%}
    {%- if custom_schema_name is none -%}

        {{ default_schema }}

    {%- else -%}

        {{ custom_schema_name | trim }}_{{ default_schema }}

    {%- endif -%}

{%- endmacro %}

この状態でdbtを実行すると、スキーマ名が変わりました。ロジックが入れ替わっていますね。

おわりに

ドキュメントによれば、中間テーブルのようなものはステージングスキーマに隠しておき、完成版だけ本来のスキーマに格納する、といった使い方もできるようです。

ただ、あまりにも大量で複雑なスキーマ構成にはできない(というか非常に大変)ので、なるべくdbtの仕様に合わせるような構成を予め検討しておいた方が、後々幸せになるかと思います。