BigQuery の全テーブルのレコード件数やサイズを保存して、前日からの変化を確認する
BigQuery のテーブル別レコード数を履歴として保存して、その変化を見ることで期待した操作が行われているか(逆に、意図しない操作をしていないか)をチェックする方法を考えました。 全体的にどういう変化が起きたのかをざっくり確認したい、というのが目的です。
具体的には、INFORMATION_SCHEMA.PARTITIONS ビュー*1のレコードを履歴として保存して、指定した日とその前日分を比較しています。
ソースコード
Python スクリプトを実行する方式をとっていますが、レコード操作は SQL でやっています。Jinja パラメータを置換すれば、そのまま使えるはずです。以下では SQL をベースにやっていることを紹介します。
やっていること
データセット一覧の取得
INFORMATION_SCHEMA.SCHEMATA ビューを参照して、データセット一覧を取得します。 この一覧をもとに、次の手順で参照する PARTITIONS ビューの対象データセットを指定します。
SELECT SCHEMA_NAME FROM region-{{ region }}.INFORMATION_SCHEMA.SCHEMATA
https://github.com/tosh2230/bigquery-table-history/blob/main/src/sql/get_target_datasets.sql
PARTITIONS ビューのレコードを日次保存
データセットごとの INFORMATION_SCHEMA.PARTITIONS ビューから、履歴テーブルである information_schema_partitions_history
へ INSERT します。
INFORMATION_SCHEMA.PARTITIONS ビューでは、テーブル内のレコード件数やサイズ、最終更新日などを確認できます。名前のとおり、パーティション別にレコードがつくられています。 このビューで参照できるレコードを、CURRENT_TIMESTAMP と共に別テーブルに保存します。これを日次で行います。
INSERT INTO {{ history_dataset }}.information_schema_partitions_history SELECT CURRENT_TIMESTAMP() as recorded_at, table_catalog, table_schema, table_name, partition_id, total_rows, total_logical_bytes, total_billable_bytes, last_modified_time, storage_tier FROM {{ target_dataset }}.INFORMATION_SCHEMA.PARTITIONS
https://github.com/tosh2230/bigquery-table-history/blob/main/src/sql/add_records.sql
前日との差分抽出
基準日とその前日のレコード群の対象差 (A△B = (A−B)∪(B−A)) をとります*2。
この結果が、指定した日付に BigQuery で起きた変化です。
パーティションごとに件数を確認できるので、意図せず過去分のレコードに手を加えていた...といった事態に気づけたり、テーブルサイズの推移をチェックしたりできそうです。
WITH today AS ( SELECT latest.* FROM ( SELECT table_catalog, table_schema, table_name, partition_id, ARRAY_AGG(history ORDER BY history.recorded_at DESC LIMIT 1)[OFFSET(0)] AS latest FROM {{ history_dataset }}.information_schema_partitions_history AS history WHERE recorded_at >= TIMESTAMP("{{ base_date }}", "Asia/Tokyo") AND recorded_at < TIMESTAMP_ADD(TIMESTAMP("{{ base_date }}", "Asia/Tokyo"), INTERVAL 1 DAY) AND table_schema != "{{ history_dataset }}" AND table_name != "information_schema_partitions_history" GROUP BY table_catalog, table_schema, table_name, partition_id ) ), yesterday AS ( SELECT latest.* FROM ( SELECT table_catalog, table_schema, table_name, partition_id, ARRAY_AGG(history ORDER BY history.recorded_at DESC LIMIT 1)[OFFSET(0)] AS latest FROM {{ history_dataset }}.information_schema_partitions_history AS history WHERE recorded_at >= TIMESTAMP_SUB(TIMESTAMP("{{ base_date }}", "Asia/Tokyo"), INTERVAL 1 DAY) AND recorded_at < TIMESTAMP("{{ base_date }}", "Asia/Tokyo") AND table_schema != "{{ history_dataset }}" AND table_name != "information_schema_partitions_history" GROUP BY table_catalog, table_schema, table_name, partition_id ) ) SELECT FORMAT_TIMESTAMP("%F %T", today.recorded_at, "Asia/Tokyo") AS recorded_at_jst, diff.* FROM ( SELECT * EXCEPT(recorded_at) FROM today EXCEPT DISTINCT SELECT * EXCEPT(recorded_at) FROM yesterday ) AS diff LEFT OUTER JOIN today ON diff.table_catalog = today.table_catalog AND diff.table_schema = today.table_schema AND diff.table_name = today.table_name UNION ALL SELECT FORMAT_TIMESTAMP("%F %T", yesterday.recorded_at, "Asia/Tokyo") AS recorded_at_jst, diff.* FROM ( SELECT * EXCEPT(recorded_at) FROM yesterday EXCEPT DISTINCT SELECT * EXCEPT(recorded_at) FROM today ) AS diff LEFT OUTER JOIN yesterday ON diff.table_catalog = yesterday.table_catalog AND diff.table_schema = yesterday.table_schema AND diff.table_name = yesterday.table_name ORDER BY table_catalog, table_schema, table_name, partition_id, recorded_at_jst
https://github.com/tosh2230/bigquery-table-history/blob/main/src/sql/diff_records.sql