0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

BigQueryのテーブル参照数を数える ( 日付別テーブル ワイルドカード対応 )

Last updated at Posted at 2020-05-03

FollowしていたGCPUGのMediumで、興味深い記事を見つけました。

おお、こういったデータセットやジョブのメタデータがQueryで取得できたんですね!知りませんでした。

これに触発されて、参照されたテーブルをさっと確認して、参照されていないテーブルをリストして、カオスになったBigQueryを整理する際に使えたらいいなと、思いました。

考え方としては、

テーブルの一覧を myDataset.INFORMATION_SCHEMA.TABLES から取得して、これに、上記のQiitaの記事で記載の参照数をLEFT JOINしてやれば 参照のないテーブルが見つかるなと思った次第です。

で、、サクッとやってみてすぐに分かったのですが、、、日付別テーブルで管理しているテーブルのワイルドカードでのアクセスがうまくJOINできない😿

そこでいろいろSQLを頑張って、以下のような順番で実現してみました。

  1. myDataset.INFORMATION_SCHEMA.TABLES を使ってテーブル一覧 tables を取得
  2. テーブル一覧 tables の中から、_YYYYMMDD となっているテーブルを探してそれに対しては、_YYYYMM, _YYYY といった具合でワイルドカードアクセスできるテーブル名を縦持ちで table_seqとして作成
  3. table_seqのままだと作ったテーブル名が重複が多いので、null除去と、ユニーク化するために、table_listを作成
  4. 一方、参照テーブルと参照数を reference_jobs で出すが、参照テーブル名では、末尾が * のものがあれば * を削除
  5. 1と2をLEFT JOINするが、更に、table_YYYYMMDD 由来の table名を、table_に集約・集計

なお、myDataset を確認したいデータセットで指定してください。31日前までのJOBを集計します。INFORMATION_SCHEMA.JOBS_BY_*には 180 日間の履歴が残っているようですが、絞ることでコスト削減できます。

with tables as (
SELECT
table_catalog
, table_schema
, table_name
, table_type
, creation_time
FROM
  myDataset.INFORMATION_SCHEMA.TABLES
)
, table_seq as (
select table_catalog, table_schema, table_name, table_type, creation_time from tables
UNION ALL SELECT table_catalog, table_schema, IF (REGEXP_CONTAINS(table_name, '_[0-9]{8}'), SUBSTR(table_name, 0, CHAR_LENGTH(table_name)-1), NULL), table_type, creation_time from tables
UNION ALL SELECT table_catalog, table_schema, IF (REGEXP_CONTAINS(table_name, '_[0-9]{8}'), SUBSTR(table_name, 0, CHAR_LENGTH(table_name)-2), NULL), table_type, creation_time from tables
UNION ALL SELECT table_catalog, table_schema, IF (REGEXP_CONTAINS(table_name, '_[0-9]{8}'), SUBSTR(table_name, 0, CHAR_LENGTH(table_name)-3), NULL), table_type, creation_time from tables
UNION ALL SELECT table_catalog, table_schema, IF (REGEXP_CONTAINS(table_name, '_[0-9]{8}'), SUBSTR(table_name, 0, CHAR_LENGTH(table_name)-4), NULL), table_type, creation_time from tables
UNION ALL SELECT table_catalog, table_schema, IF (REGEXP_CONTAINS(table_name, '_[0-9]{8}'), SUBSTR(table_name, 0, CHAR_LENGTH(table_name)-5), NULL), table_type, creation_time from tables
UNION ALL SELECT table_catalog, table_schema, IF (REGEXP_CONTAINS(table_name, '_[0-9]{8}'), SUBSTR(table_name, 0, CHAR_LENGTH(table_name)-6), NULL), table_type, creation_time from tables
UNION ALL SELECT table_catalog, table_schema, IF (REGEXP_CONTAINS(table_name, '_[0-9]{8}'), SUBSTR(table_name, 0, CHAR_LENGTH(table_name)-7), NULL), table_type, creation_time from tables
UNION ALL SELECT table_catalog, table_schema, IF (REGEXP_CONTAINS(table_name, '_[0-9]{8}'), SUBSTR(table_name, 0, CHAR_LENGTH(table_name)-8), NULL), table_type, creation_time from tables
)
, table_list as (
select table_catalog, table_schema, table_name, table_type, min(creation_time) as creation_time
from table_seq
group by table_catalog, table_schema, table_name, table_type
)
,
reference_jobs as
(
select
  t.project_id
, t.dataset_id
, REGEXP_REPLACE(t.table_id, '\\*$' , '') as table_id
, max(j.start_time) as last_query_date
, count(1) as ref_nums -- テーブルの参照回数を取得します。
from
  `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT j
    -- referenced_tables カラムの配列を行へ変換します。
    cross join
      unnest(j.referenced_tables) t
where
  -- creation_time がパーティショニング カラムとなっているため、
  -- コスト節約のために、このカラムでの絞り込みを行うことを推奨します。
  DATE_DIFF(current_date(), DATE(j.creation_time) , DAY) < 31
and j.job_type = 'QUERY' -- クエリ ジョブのみを検索対象とします。
and j.statement_type = 'SELECT' -- select クエリのみを検索対象とします。
and j.state = 'DONE' -- 実行が完了したジョブのみを検索対象とします。
and j.error_result is null -- 正常終了したジョブのみを検索対象とします。
-- 参照テーブル(プロジェクト ID、データセット ID、テーブル ID)ごとに
-- グループ化して集計します。
group by
  t.project_id
, t.dataset_id
, 3
)

SELECT
l.table_catalog as project_name
, l.table_schema as dataset_name
, REGEXP_REPLACE(l.table_name, '_[0-9]*$' , '_') as table_name
, min(l.creation_time) as first_createion_time
, max(j.last_query_date) as last_query_date
, sum(IFNULL(j.ref_nums, 0)) as ref_nums
from table_list as l
left join reference_jobs as j
  ON l.table_schema = j.dataset_id AND l.table_name = j.table_id
group by project_name, dataset_name, table_name
order by ref_nums DESC
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?