materialized = table で dbt run のパフォーマンスを改善する
こんにちは、 @kz_morita です。
普段 dbt でデータ変換を実装しているのですが、データモデルで重い処理があると dbt run の実行時間が増えてきます。
重い処理 dbt でモデルを構築していたのですが、SQL で URL に含まれるクエリパラメータをパースするような処理が重かったです。
具体的には以下のような SQL です。
withraw_dataas(selectid,urlfrom{{ref('source_table')}})selectid,url,-- パラメータ foo の値を抽出するための正規表現 regexp_extract(url,'.*[?&]foo=([^&]+)',1)asfoo_value,-- パラメータ bar の値を抽出するための正規表現 regexp_extract(url,'.*[?&]bar=([^&]+)',1)asbar_valuefromraw_dataこのモデルが、後続の様々なモデルから参照されていたのですが処理が重く dbt run に 30 分位かかっていました。 正規表現を使うのは CPU ヘビーな処理になりやすくボトルネックになりやすいのでここを改善しようとしました。
materialized = table で高速化 問題は、dbt のデフォルトの materialize が view になっていることです。
後続のモデルから複数参照されるモデルのため、view 担っている場合参照されるたびに正規表現によるパース処理が走ります。 パースは一度で良かったので、materialize = table にすることで高速化を試みました。
やり方は簡単で、SQL の先頭に以下のような config を書くだけでよいです。
{{config(materialized='table')}}withraw_dataas(selectid,urlfrom{{ref('source_table')}})selectid,url,-- パラメータ foo の値を抽出するための正規表現 regexp_extract(url,'.*[?&]foo=([^&]+)',1)asfoo_value,-- パラメータ bar の値を抽出するための正規表現 regexp_extract(url,'.*[?&]bar=([^&]+)',1)asbar_valuefromraw_dataこのようにすると一度パースされたパラメータがテーブルに保持されるため正規表現の処理が複数回走らなくなりその結果として実行時間を大幅に減らすことができました。 具体的には、30 分かかっていたところが 3 分ほどになりました。
今回の様な計算コストが高い処理などを行う場合 materialization を table にすることで高速化が期待できます。ただし、データをリアルタイムで反映したいようなケースの場合テーブルだと dbt run が走ったタイミングでしか同期されないため注意が必要です。