❄️

【dbt】SnowflakeのDB名に二重引用符をつけてsnapshotでハマった話

2023/08/16に公開

はじめに

dbtはsnapshotやincrementalがあって便利なのですがSnowflake準拠の引用符で囲まれていない識別子でオブジェクトを作成しないと動きはするのですが想定と違った動作なったりします。
なので、設定ファイルの読み込み順序や回避策を備忘録として残したいと思います。
(将来の自分を含め)どなたかの問題解決に役に立てれば幸いです。

環境

  • Snowflake: 7.27.1
  • Python: 3.9.13
  • dbt-core: 1.5.3
  • dbt-snowflake: 1.5.2

どんなところにハマったの?

Snowflakeで二重引用符を使ったDBを作成して、dbtのquoting設定をSnowflakeのデフォルトで動かすとsnapshotが常にcreate or repalceをしてしまい履歴保持ができないとこにハマりました。

回避策

下記のようにそれぞれのファイルを修正するとsnapshotが履歴保持をするようになりました。
※<>で囲まれている内容は任意に置き換えてご使用ください。

dbt_project.yml

デフォルトの設定から下記に変更

quoting:
  database: true

profiles.yml

database: '"<db_name>"'からdatabase: '<db_name>'に修正

<pj_name>:
  outputs:
    <target_name>:
      # database: '"<db_name>"' ## こちらだと履歴保持が動作しない
      database: '<db_name>'
      ...

sourcesの設定

2通りの回避策があります。

quotingdatabase: trueを追加

sourcesの設定では`quotingを使えるため下記のように追加

sources:
  - name: <source_name>
    quoting:
      database: true
    ...

database: '"<db_name>"'を追加

sources:
  - name: <source_name>
    database: '"<db_name>"'
    ...

上記で問題を回避できる理由

ここ先は推測なので、読み飛ばしてもらっても大丈夫です。

前提

dbt_project.ymlの設定は下記の様になっています。

quoting:
  database: true

原因1:connection_nameプロパティの文字列内に二重引用符が混入する

dbt --debugで確認した結果、connection_nameプロパティが影響していると考えられます。

profiles.ymlでdatabase: '<db_name>'と定義した場合のdbt内部で保持するパラメタ

 {"app": "dbt", "dbt_version": "1.5.3", "profile_name": "<pj_name>", "target_name": "<target_name>", "connection_name": "list_<db_name>"}

扱う文字列:"list_<db_name>"
上記なら処理に問題はないと考えられます。

profiles.ymlでdatabase: '"<db_name>"'と定義した場合のdbt内部で保持するパラメタ

 {"app": "dbt", "dbt_version": "1.5.3", "profile_name": "<pj_name>", "target_name": "<target_name>", "connection_name": "list_\"<db_name>\""}

扱う文字列:list_"<db_name>"
上記のような文字列がdbt内部に渡された際に正常な処理をされているか確認する必要があるかと思います。(これ以上は追えませんでした・・・)

原因2:設定ファイルの読み込み順序

引用符の問題に関しては設定ファイルの読み込み順序が関係しています。
dbtでは次の順序で設定ファイルを読み込んでいます。

  1. dbt_project.yml
  2. profiles.yml
  3. {models/seeds/snapshots}/*.yml

ここで抜けがちなのが、sourcesの設定がdbt_project.ymlのあとに呼ばれるかつquotingの設定も保持しているところです。
そのため、dbtの動作を正常にしようとdbt_project.ymlprofiles.ymlの設定をしたにも関わらず引用符の問題でdbtがうまく動作しない場合、sourcesの設定を見直してみるとうまく動く場合があります。

この回避策で新しくエラーが起こる可能性のあるオブジェクト

二重引用符が必要なテーブル名をdbtのalias設定で作成している場合に下記のエラーが起こる可能性があります。
こちらは汎化するとわかりにくいので具体的なオブジェクト名付きで記載します。

Compilation Error in model use-table (models/use/use-table.sql)
    When searching for a relation, dbt found an approximate match. Instead of guessing 
    which relation to use, dbt will move on. Please delete "K-HAMAGUCHI-DB"."DWH"."USE-TABLE", or rename it to be less ambiguous.
    Searched for: K-HAMAGUCHI-DB.DWH."USE-TABLE"
    Found: "K-HAMAGUCHI-DB"."DWH"."USE-TABLE"

この問題に関してはGithubで議論されていましたが、修正の対象ではないようです。(そもそも推奨から外れているのでテーブル名を見直して作り直してほしいという意図を感じました)
なのでできる限りテーブル名は引用符で囲まれていない識別子で作成することをおすすめします。

さいごに

dbtはSnowflakeとも相性がよく使いやすいツールですが、思わぬところで地雷を踏み抜きました。。ただ、このおかげでdbtの設定ファイルを読み込む順序・推奨するオブジェクト名の方針・--debugを使った内部処理まで見れて勉強になりました。そもそも二重引用符を使ったオブジェクトを作成しないことが最も安全ですが、どうしても二重引用符が必要なオブジェクトに対してdbtを使うことになった際はこの記事を見ていただけると幸いです。
この修正でdbt docsでメタデータを引っ張ってこれるようになったのでとても嬉しい!!

Discussion