🫶

BigqueryとLookerstudioの監視まとめ

2024/02/02に公開

背景

監視周りの情報を久しぶりに調べなおしたので簡単にまとめた

目的

  • みなさんも簡単に監視を始められるようにする

Caveat

一部どうしても置き換えてもらう必要のある変数がある

gcp_project_id = hoge
gcp_dataset_id = fuga

この記事では基本的に Bigquery の INFORMATION_SCHEMA を使う
INFORMATION_SCHEMA はアップデートも頻繁にあるらしい、ので動かない場合はコメントくださるとうれしい

https://cloud.google.com/bigquery/docs/information-schema-intro

内容

テーブルの最終更新日

SELECT * FROM `gcp_project_id.gcp_dataset_id`.__TABLES__

実は上は非推奨らしいので、下を使うこと

SELECT * FROM `gcp_project_id.gcp_dataset_id`..INFORMATION_SCHEMA.PARTITIONS

https://www.yasuhisay.info/entry/2021/12/23/083000

データセットのレコード総数とデータ総量

SELECT
  table_schema,  SUM(total_rows) AS total_rows,  ROUND(SUM(total_logical_bytes) / (1024 * 1024), 2) AS size_mb,  ROUND(SUM(total_logical_bytes) / (1024 * 1024 * 1024), 2) AS size_gb
FROM
  `region-asia-northeast1`.INFORMATION_SCHEMA.TABLE_STORAGEGROUP BY
  table_schema
SELECT * FROM `region-asia-northeast1`.INFORMATION_SCHEMA.SCHEMATASELECT * FROM `gcp_dataset_id`.INFORMATION_SCHEMA.TABLES

https://www.niandc.co.jp/tech/20200923_1893/

10日以上アクセスがないデータセット

SELECT
  s.schema_name,  j.latest_creation_timeFROM
  `region-asia-northeast1`.INFORMATION_SCHEMA.SCHEMATA AS s
LEFT JOIN (
  SELECT
    referenced_table.dataset_id AS dataset_id,    MAX(creation_time) AS latest_creation_time
  FROM
    `region-asia-northeast1`.INFORMATION_SCHEMA.JOBS_BY_PROJECT,    UNNEST(referenced_tables) AS referenced_table
  WHERE
    referenced_table.table_id != '__TABLES__'  GROUP BY
    referenced_table.dataset_id ) AS j
ON
  j.dataset_id = s.schema_name  -- ジョブメタデータにアクセス履歴がない、または最終クエリ実行日より10日以上経過したデータセット
WHERE
  j.latest_creation_time IS NULL
  OR j.latest_creation_time < TIMESTAMP_SUB(TIMESTAMP_TRUNC(CURRENT_TIMESTAMP(), DAY), INTERVAL 10 DAY) ;

https://lab.astamuse.co.jp/entry/2020/09/23/bigquery

高額クエリ

SELECT
 user_email, SUM(total_bytes_processed) AS total_bytes_processed, -- Byte to TB
 SUM(total_bytes_processed) / 1024 / 1024 / 1024 /1024 AS total_TB_processed, -- TB to Dollar
 -- asia-northeast1を想定し$6/TB
 SUM(total_bytes_processed) / 1024 / 1024 / 1024 /1024 * 6.0 AS Charges_Dollar,FROM
`region-asia-northeast1`.INFORMATION_SCHEMA.JOBS_BY_PROJECTWHERE
 DATE(creation_time) BETWEEN DATE_ADD(CURRENT_DATE('Asia/Tokyo'), INTERVAL -30 DAY ) AND CURRENT_DATE('Asia/Tokyo')
GROUP BY 1ORDER BY 2 DESC

https://qiita.com/na0/items/479307cc75b932c2731f

https://www.niandc.co.jp/tech/20200923_1893/

特定のデータセット/テーブルを参照しているクエリの取得

SELECT
  user_email,  COUNT(user_email) AS query_count
FROM
  `region-asia-northeast1`.INFORMATION_SCHEMA.JOBS_BY_PROJECTWHERE
  DATE(creation_time) BETWEEN DATE_ADD(CURRENT_DATE('Asia/Tokyo'), INTERVAL -30 DAY )
  AND CURRENT_DATE('Asia/Tokyo')
  AND REGEXP_CONTAINS(query, r'`gcp_dataset_id.*`')
GROUP BY
  1ORDER BY
  2 DESC

頻繁に参照されているテーブルの把握

SELECT
  t.project_id,  t.dataset_id,  t.table_id,  COUNT(1) AS ref_nums -- テーブルの参照回数
FROM
  `region-asia-northeast1`.INFORMATION_SCHEMA.JOBS_BY_PROJECT j
  -- referenced_tables カラムの配列を行へ変換
CROSS JOIN
  UNNEST(j.referenced_tables) t
WHERE
  -- creation_time がパーティショニング カラムとなっているため、
  -- コスト節約のために、このカラムでの絞り込みを行うことを推奨
  DATE(j.creation_time) = CURRENT_DATE()
  AND j.job_type = 'QUERY' -- クエリ ジョブのみを検索対象
  AND j.statement_type = 'SELECT' -- select クエリのみを検索対象
  AND j.state = 'DONE' -- 実行が完了したジョブのみを検索対象
  AND j.error_result IS NULL -- 正常終了したジョブのみを検索対象
GROUP BY
  t.project_id,  t.dataset_id,  t.table_idORDER BY
  ref_nums DESC
LIMIT
  5

https://zenn.dev/satokiyo/articles/20231014-with-recursive

https://medium.com/google-cloud-jp/bigquery-table-usage-investigation-836c31eafe4b

長時間稼働クエリ

SELECT
  DISTINCT job_id,  FORMAT_TIMESTAMP('%Y-%m-%d %H:%M:%S', creation_time, 'Asia/Tokyo') AS jst_creation_time,  FORMAT_TIMESTAMP('%Y-%m-%d %H:%M:%S', end_time, 'Asia/Tokyo') AS jst_end_time,  TIMESTAMP_DIFF(
  IF
    (end_time IS NULL, CURRENT_TIMESTAMP(),end_time), creation_time,minute) AS total_exe_minites,  state,  user_email,  query,  TRUNC(total_bytes_processed/(1024*1024*1024), 1) AS total_gb
FROM
  `gcp_project_id.gcp_dataset_id`.INFORMATION_SCHEMA.JOBS_BY_PROJECTWHERE
  DATE(creation_time,'Asia/Tokyo') = CURRENT_DATE('Asia/Tokyo')
  AND TIMESTAMP_DIFF(
  IF
    (end_time IS NULL, CURRENT_TIMESTAMP(),end_time), creation_time,minute) > 60ORDER BY
  total_exe_minites desc

定額スロット数の概算見積もり

デフォルトではオンデマンド設定になっているはずで、毎月 1TiB までは無料で使える

一部のユーザーにとっては最適なスロット数を計算することでコスト最適化ができる

SELECT
  DATE(TIMESTAMP_TRUNC(creation_time, MONTH), "Asia/Tokyo") AS month,  COUNT(1),  SUM(total_slot_ms) / (1000*60*60*24* EXTRACT(DAY
    FROM
      DATE_SUB( DATE_ADD( DATE(TIMESTAMP_TRUNC(CURRENT_TIMESTAMP(), MONTH), "Asia/Tokyo"), INTERVAL 1 MONTH ), INTERVAL 1 DAY ) )) AS avg_slots
FROM
  `region-asia-northeast1`.INFORMATION_SCHEMA.JOBS_BY_PROJECTGROUP BY
  DATE(TIMESTAMP_TRUNC(creation_time, MONTH), "Asia/Tokyo")

https://tech.plaid.co.jp/bigquery-slot-resource-optmization

https://book.st-hakky.com/data-platform/how-to-monitoring-bigquery-cost/

https://note.com/mercari_data/n/nd0889605d22e

ただし BigQuery Slot Recommender という公式のサービスがあるのでこっちを使った方がいいもしれない

https://cloud.google.com/bigquery/docs/slot-recommender

INFORMATION SCHEMAを実体化

下の参考文献にも書いてあるように INFORMATION SCHEMA は過去180日間分しか保持しない
よってそれ以上の期間で監視したい場合は実体化して保持しておこう

Data retention history of the past 180 days.

https://lab.mo-t.com/blog/mot-advent-calendar-20221214

Lookerstudioごとのクエリ量

CREATE TEMP FUNCTION
  GetLabel(labels ANY TYPE,    label_key STRING) AS ( (
    SELECT
      l.value    FROM
      UNNEST(labels) l
    WHERE
      l.key = label_key) );WITH
  job_list AS (
  SELECT
    GetLabel(labels,      "looker_studio_report_id") AS report_id,    total_bytes_billed,  FROM
    `region-asia-northeast1`.INFORMATION_SCHEMA.JOBS  WHERE
    DATE(creation_time, "Asia/Tokyo") BETWEEN DATE_SUB(CURRENT_DATE("Asia/Tokyo"), INTERVAL 30 DAY)
    AND DATE_SUB(CURRENT_DATE("Asia/Tokyo"), INTERVAL 0 DAY)
    AND GetLabel(labels,      'requestor') = 'looker_studio' )
SELECT
  report_id,  SUM(total_bytes_billed)/1024/1024/1024 AS total_gb_billed
FROM
  job_list
GROUP BY
  report_id

https://blog.g-gen.co.jp/entry/how-to-figure-out-bigquery-cost-per-looker-studio-report

エラーが出たクエリ

前提条件として cloud logging の sink の作成が必要

https://swfz.hatenablog.com/entry/2021/09/07/033531

https://zenn.dev/maretol/articles/f97390b955ecba

SELECT
  protopayload_auditlog.authenticationInfo.principalEmail,  resource.labels.project_id,  timestamp AS err_timestamp,  protopayload_auditlog.servicedata_v1_bigquery.jobCompletedEvent.job.jobConfiguration.query.query AS err_query,  protopayload_auditlog.servicedata_v1_bigquery.jobCompletedEvent.job.jobStatus.error.message AS err_message
FROM
  logging.cloudaudit_googleapis_com_data_accessWHERE
  protopayload_auditlog.methodName = 'jobservice.jobcompleted'  AND severity = 'ERROR'  AND timestamp >= TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL -1 day)

https://zenn.dev/y2000/articles/8451e2015792fd16c904

その他の便利クエリ

公式が紹介しているクエリも非常に便利なものが多いので一度見て欲しい

https://cloud.google.com/blog/ja/products/data-analytics/bigquery-audit-logs-pipelines-analysis

https://cloud.google.com/architecture/exporting-stackdriver-logging-for-security-and-access-analytics

Lookerstudioの弱アクセスログ

lookerstudio に ga4 の設定を行うことができ、どのページがよく閲覧されているかがわかる

https://support.google.com/looker-studio/answer/7410792?hl=en

https://googleanalytics-laboratory.com/columns/9

Lookerstudioの強アクセスログ

上のログだけではたとえば誰が見たかはわからないので特定の部署等の需要は把握しずらい

そこでこちらのログを使うことで「いつ、誰が、どこから、どのレポートへアクセスしたか」などを確認できる。エクスポートなどのイベントのログも取れるようだ

しかし、強い権限が必要なので社内の情シスに依頼が必要だと思われる、私はそうだった

https://support.google.com/a/answer/9690662?hl=en

https://glass-inc.jp/media/looker-studio-ga4-user-level-analytics/

怖い話

最近Twitterで話題になってたので貼っておく

https://qiita.com/itkr/items/745d54c781badc148bb9

https://futurismo.biz/bigquery-fire/

参考

https://qiita.com/k_0120/items/175a18dae34dce0ddbc5

https://medium.com/@niloy.swe/how-to-monitor-bigquery-usage-and-costs-on-gcp-with-interactive-visualizations-in-looker-studio-f2c1d44d99d2

https://www.m3tech.blog/entry/2020/12/18/113000
https://cloud.google.com/bigquery/pricing?hl=ja

https://giginc.co.jp/blog/giglab/bigquery-price

Discussion