【dbt】SnowflakeのDB名に二重引用符をつけてsnapshotでハマった話
はじめに
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通りの回避策があります。
quoting
でdatabase: 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
connection_name
プロパティの文字列内に二重引用符が混入する
原因1:dbt --debug
で確認した結果、connection_name
プロパティが影響していると考えられます。
database: '<db_name>'
と定義した場合のdbt内部で保持するパラメタ
profiles.ymlで {"app": "dbt", "dbt_version": "1.5.3", "profile_name": "<pj_name>", "target_name": "<target_name>", "connection_name": "list_<db_name>"}
扱う文字列:"list_<db_name>"
上記なら処理に問題はないと考えられます。
database: '"<db_name>"'
と定義した場合のdbt内部で保持するパラメタ
profiles.ymlで {"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では次の順序で設定ファイルを読み込んでいます。
- dbt_project.yml
- profiles.yml
- {models/seeds/snapshots}/*.yml
ここで抜けがちなのが、sources
の設定がdbt_project.ymlのあとに呼ばれるかつquoting
の設定も保持しているところです。
そのため、dbtの動作を正常にしようとdbt_project.yml
やprofiles.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