目次
今回はSnowflakeの超便利関数「GET_OBJECT_REFERENCES」を物理テーブル化するPROCEDUREを作ってみました。
今回は前回投稿した記事、「PythonでSnowflakeのGET_OBJECT_REFERENCES関数を物理テーブル化する」の続きという位置づけですので、ぜひこちらもご覧ください🙇
(GET_OBJECT_REFERENCES関数については以前の記事で紹介しております。)
前回のおさらい
前回はPythonでGET_OBJECT_REFERENCES関数を物理テーブル化していきました。
今回も、前回作成したテーブルと同じものを作ります。
今回使用するデータも前回と同じです。
- TEST_A/B
- テーブル
- TEST_C
- TEST_Aを参照するビュー
- TEST_D
- TEST_Bを参照するビュー
- TEST_E
- TEST_C/Dを参照するビュー
物理化してみた
今回作成したPROCEDUREは以下になります。
CREATE OR REPLACE PROCEDURE BIRD_DEMO.TO_TABLE.CREATE_GET_OBJECT_REFERENCES() | |
RETURNS VARCHAR | |
LANGUAGE JAVASCRIPT | |
AS | |
$$ | |
var sql_command1 = `show views in database BIRD_DEMO;`; | |
var stmt1 = snowflake.createStatement({sqlText : sql_command1}); | |
var rs1 = stmt1.execute(); | |
var objectReferences = []; | |
while (rs1.next()) { | |
// Snowflakeが提供するViewは対象外 | |
if (rs1.schema_name == "INFORMATION_SCHEMA") { | |
continue; | |
} | |
var sql_command2 = `select * from table(get_object_references( | |
database_name => '` + rs1.database_name + `' | |
, schema_name => '` + rs1.schema_name + `' | |
, object_name => '` + rs1.name + `'));`; | |
var stmt2 = snowflake.createStatement({sqlText : sql_command2} | |
); | |
var rs2 = stmt2.execute(); | |
while (rs2.next()) { | |
// stmt2を実行して得られた値で連想配列を作成し、配列に追加 | |
var objectReference = { | |
database_name : rs2.DATABASE_NAME | |
, schema_name : rs2.SCHEMA_NAME | |
, object_name : rs2.OBJECT_NAME | |
, referenced_database_name : rs2.REFERENCED_DATABASE_NAME | |
, referenced_schema_name : rs2.REFERENCED_SCHEMA_NAME | |
, referenced_object_name : rs2.REFERENCED_OBJECT_NAME | |
, referenced_object_type : rs2.REFERENCED_OBJECT_TYPE | |
}; | |
objectReferences.push(objectReference); | |
} | |
} | |
// 配列をJSON文字列化 | |
var objectReferencesJson = JSON.stringify(objectReferences); | |
var sql_command3 = `create or replace temporary table BIRD_DEMO.TO_TABLE.GET_OBJECT_REFERENCES_TEMP | |
(REFERENCE variant) as select ('` + objectReferencesJson + `');`; | |
var stmt3 = snowflake.createStatement({sqlText : sql_command3}); | |
var rs3 = stmt3.execute(); | |
// flatten関数を使用し、JSON文字列のkeyをカラムとして構造化 | |
var sql_command4 = `create or replace table BIRD_DEMO.TO_TABLE.GET_OBJECT_REFERENCES_2 | |
as | |
select | |
value:database_name::varchar AS DATABASE_NAME | |
, value:schema_name::varchar AS SCHEMA_NAME | |
, value:object_name::varchar AS OBJECT_NAME | |
, value:referenced_database_name::varchar AS REFERENCED_DATABASE_NAME | |
, value:referenced_schema_name::varchar AS REFERENCED_SCHEMA_NAME | |
, value:referenced_object_name::varchar AS REFERENCED_OBJECT_NAME | |
, value:referenced_object_type::varchar AS REFERENCED_OBJECT_TYPE | |
from | |
BIRD_DEMO.TO_TABLE.GET_OBJECT_REFERENCES_TEMP | |
, lateral flatten ( input => REFERENCE)`; | |
var stmt4 = snowflake.createStatement({sqlText : sql_command4}); | |
var rs4 = stmt4.execute(); | |
return 'Create Table GET_OBJECT_REFERENCES Done.'; | |
$$ | |
; |
処理の流れをブロックごとに記載していきます。
1. show viewsコマンドでviewの一覧を取得し、ループさせてGET_OBJECT_REFERENCES関数を実行する
var sql_command1 = `show views in database BIRD_DEMO;`; | |
var stmt1 = snowflake.createStatement({sqlText : sql_command1}); | |
var rs1 = stmt1.execute(); | |
var objectReferences = []; | |
while (rs1.next()) { | |
// Snowflakeが提供するViewは対象外 | |
if (rs1.schema_name == "INFORMATION_SCHEMA") { | |
continue; | |
} | |
var sql_command2 = `select * from table(get_object_references( | |
database_name => '` + rs1.database_name + `' | |
, schema_name => '` + rs1.schema_name + `' | |
, object_name => '` + rs1.name + `'));`; | |
var stmt2 = snowflake.createStatement({sqlText : sql_command2} | |
); | |
var rs2 = stmt2.execute(); |
ここまでは前回のPythonで実装した処理と同じです。
2. 結果をループさせて連想配列化し、配列にpush
while (rs2.next()) { | |
// stmt2を実行して得られた値で連想配列を作成し、配列に追加 | |
var objectReference = { | |
database_name : rs2.DATABASE_NAME | |
, schema_name : rs2.SCHEMA_NAME | |
, object_name : rs2.OBJECT_NAME | |
, referenced_database_name : rs2.REFERENCED_DATABASE_NAME | |
, referenced_schema_name : rs2.REFERENCED_SCHEMA_NAME | |
, referenced_object_name : rs2.REFERENCED_OBJECT_NAME | |
, referenced_object_type : rs2.REFERENCED_OBJECT_TYPE | |
}; | |
objectReferences.push(objectReference); | |
} | |
} |
同じkeyの連想配列を格納した配列が出来上がります。
3. 2の配列の中の連想配列をJSON化し、Snowflakeでtempテーブル化
// 配列をJSON文字列化 | |
var objectReferencesJson = JSON.stringify(objectReferences); | |
var sql_command3 = `create or replace temporary table BIRD_DEMO.TO_TABLE.GET_OBJECT_REFERENCES_TEMP | |
(REFERENCE variant) as select ('` + objectReferencesJson + `');`; | |
var stmt3 = snowflake.createStatement({sqlText : sql_command3}); | |
var rs3 = stmt3.execute(); |
SnowflakeはJSON等の半構造化データをサポートしています。(詳しくはこちら)
tempテーブルを確認してみます。
select | |
* | |
from | |
BIRD_DEMO.TO_TABLE.GET_OBJECT_REFERENCES_TEMP |
問題なく作成されています。
4. 3のtempテーブルをフラット化し、GET_OBJECT_REFERENCES関数の結果と同じ構造のテーブルを作成
// flatten関数を使用し、JSON文字列のkeyをカラムとして構造化 | |
var sql_command4 = `create or replace table BIRD_DEMO.TO_TABLE.GET_OBJECT_REFERENCES_2 | |
as | |
select | |
value:database_name::varchar AS DATABASE_NAME | |
, value:schema_name::varchar AS SCHEMA_NAME | |
, value:object_name::varchar AS OBJECT_NAME | |
, value:referenced_database_name::varchar AS REFERENCED_DATABASE_NAME | |
, value:referenced_schema_name::varchar AS REFERENCED_SCHEMA_NAME | |
, value:referenced_object_name::varchar AS REFERENCED_OBJECT_NAME | |
, value:referenced_object_type::varchar AS REFERENCED_OBJECT_TYPE | |
from | |
BIRD_DEMO.TO_TABLE.GET_OBJECT_REFERENCES_TEMP | |
, lateral flatten ( input => REFERENCE)`; | |
var stmt4 = snowflake.createStatement({sqlText : sql_command4}); | |
var rs4 = stmt4.execute(); |
flatten関数を使用することで、半構造化データを構造化しています。(詳しくはこちら)
ちなみに、flatten関数を使用した結果をそのまま出力すると以下になります。
select | |
* | |
from | |
BIRD_DEMO.TO_TABLE.GET_OBJECT_REFERENCES_TEMP | |
, lateral flatten ( input => REFERENCE) |
配列の要素ごとにレコード化されていますね。
select句で「value:キー名」と指定して、値を取り出すことができます。
それでは実行結果を確認してみましょう。
select | |
* | |
from | |
BIRD_DEMO.TO_TABLE.GET_OBJECT_REFERENCES_2 |
しっかり物理化されています!👏
実行時間
ひとつ課題点としては、当然ですがViewの数が多いと実行時間が増えてしまいます。
業務で試した際、View数107で約1分かかりました。
Pythonで実装したものも同じくらい時間がかかるので、おそらく全View分のGET_OBJECT_REFERENCES関数を実行するところがネックになっていると思われます。
おわりに
いかがだったでしょうか。
PROCEDUREで実装するときに、Python用コネクタAPIの「executemany」メソッドにあたるものが見つからなったため、違うロジックで実装してみました。
噂によると、依存関係を一括して取得できるようになるという発表がSnowdayであったそうです!これは朗報ですね。
最後まで読んでいただき、ありがとうございます!🙇