Data Engineer Associate — 第 14 章
この章で学ぶこと
この章に出てくる用語
「この集計テーブルを消したら、どのダッシュボードが壊れますか」「先週この顧客テーブルを参照したのは誰ですか」「このカタログにスキーマはいくつありますか」。三つとも後から確認する問いですが、答えを持つ場所は別々です。取り違えると、監査ログを何時間眺めても依存関係は出てきません。覚え方は一行です。構造は INFORMATION_SCHEMA、依存はリネージ、行為は監査ログです。
| 情報源 | 答えられる問い | 粒度 | 無償の保持 |
|---|---|---|---|
| `INFORMATION_SCHEMA` | いま何が存在するか | 現在のメタデータ | 履歴なし |
| `system.access.table_lineage` | どのテーブルからどこへ流れたか | 読み書きイベント | 365 日 |
| `system.access.column_lineage` | どの列がどの列を作ったか | 列と列の依存 | 365 日 |
| `system.access.audit` | 誰がいつどの操作をしたか | API 呼び出し 1 件 | 365 日 |
下の三つに共通する土台が system カタログです。Unity Catalog を有効にしたアカウントには system という読み取り専用のカタログが用意され、access、billing、lakeflow、compute、query といったスキーマが並びます。中身はただの Delta テーブルで、SQL で集計できます。有効化はアカウント管理者が行い、他の利用者には `USE CATALOG` と `SELECT` が要ります。
現在の姿を知りたいときは `INFORMATION_SCHEMA` です。各カタログの直下に自動で公開される標準ビュー群で、`SCHEMATA` でスキーマ、`TABLES` でテーブル、`COLUMNS` で列、`TABLE_PRIVILEGES` で権限の一覧が返ります。
SELECT schema_name, schema_owner
FROM mycat.INFORMATION_SCHEMA.SCHEMATA;これだけは他の system テーブルと違って明示的な `SELECT` 権限が要らず、自分が権限を持つオブジェクトだけが自動で絞り込まれて返ります。カタログ直下のものはそのカタログ内しか見えず、横断したいときは `system.information_schema` を使いますが、`hive_metastore` のオブジェクトは含まれません。
画面なら Catalog Explorer の Lineage タブ、SQL なら二つのリネージテーブルです。列は 20 以上ありますが、意味を問われるのは四つです。`source_table_full_name` だけが埋まっていれば読み取りだけ、`target_table_full_name` だけなら書き込みだけ、両方なら読んで書いた 1 イベントです。`entity_type` は `NOTEBOOK`、`JOB`、`PIPELINE`、`DASHBOARD_V3`、`DBSQL_QUERY` のどれかで、実行主体が分かります。`statement_id` は SQL ウェアハウスから実行された場合にだけ入り、Query History へ辿る外部キーになります。`column_lineage` にはさらに `source_column_name` と `target_column_name` が加わります。
SELECT source_table_full_name, entity_type, created_by, event_time
FROM system.access.table_lineage
WHERE target_table_full_name = 'main.sales.sales_agg'
AND event_date >= current_date() - INTERVAL 30 DAYS;リネージは実行されたクエリの解析で作られるため宣言もタグ付けも不要ですが、Unity Catalog を経由しない操作は残りません。`spark.read.load("/mnt/raw/...")` のような DBFS パスの直読みは、列どころかテーブルのリネージも記録されません。列リネージは、値を並べただけの `INSERT` のように上流が存在しないイベントも取得しません。UC 非対応のコンピュートも同様です。system テーブルは 1 年で古い行が消えますが、Catalog Explorer とリネージ API は 2024 年 9 月 1 日以降を無期限に保持します。
監査ログは 1 行が 1 回の API 呼び出しで、`user_identity`、`action_name`、`request_params`、`audit_level` などを持ちます。`audit_level` が `ACCOUNT_LEVEL` の行は特定のワークスペースに属さないため、`workspace_id` が `0` で記録されます。既定ではコマンドの本文は残りません。管理コンソールの Advanced タブで詳細監査ログ (`enableVerboseAuditLogs`) を有効にすると、`notebook` と `jobs` の `runCommand`、`databrickssql` の `commandSubmit` と `commandFinish` が追加され、`request_params` に `commandText` が入ります。
行フィルタや列マスク付きテーブルの監査では、誰が叩いたかを `system.access.audit`、どのテーブルと列が読まれたかを `table_lineage` と `column_lineage` で見て組み合わせます。`_delta_log` の JSON やクラスタ上の `/var/log` は、アクセス主体を記録しておらずノード終了で消えるため証跡になりません。検索クエリ例と長期保管の設計は記事「Databricks Audit Logs」(`/articles/databricks/audit-logs/`) に譲ります。
確認 — 穴あけ 3 問
0 / 3
空欄を押すと選択肢が出ます。間違えても減点はありません。
system.access.table_lineage が保持するのは直近 日分である。
実行された SQL 本文を監査ログに残すには、ワークスペース設定 を有効にする。
いまカタログにどんなスキーマがあるかを一覧するには を使う。
Databricks を使い始めた組織がまず戸惑うのは、請求書が二通届くことです。Databricks からの請求と、AWS / Azure / Google Cloud からの請求が別々に来ます。不備ではなく設計です。Databricks は計算資源の利用料だけを課金し、VM やストレージやネットワークの料金はクラウド事業者が直接請求します。分かれているので、利用者が自分でクラウド事業者と結んだリザーブドインスタンスや割引契約がそのまま効きます。片方だけを見て安いと判断すると、月末にほぼ倍の金額を見ることになります。
Databricks 側の課金単位が DBU です。1 時間あたりの処理能力を表す単位で、課金の刻みは秒単位です。1 時間走らせたら必ず 1 DBU、という意味ではありません。消費量はノード台数と VM のスペックで決まり、単価はワークロード種別で分かれた SKU ごとに違います。同じ処理でも、対話用の `STANDARD_ALL_PURPOSE_COMPUTE` とジョブ専用の `STANDARD_JOBS_COMPUTE` では単価が違います。つまり請求額は「DBU 消費量 × SKU 単価 × 時間」と「クラウド事業者からの VM・ストレージ・ネットワーク費用」の合算です。固定月額ではなく、開発用クラスタが無料になる仕組みもありません。
ここが試験でも実務でもつまずく点です。使用量を記録する `system.billing.usage` には金額の列がありません。あるのは `usage_unit` (通常 `DBU`) と `usage_quantity` だけです。金額にするには単価表 `system.billing.list_prices` と結合します。
| テーブル | 1 行の意味 | 覚えておく列 | 保持 |
|---|---|---|---|
| `system.billing.usage` | 使用量レコード 1 件 | `sku_name` / `usage_quantity` / `usage_date` / `custom_tags` / `usage_metadata` / `record_type` | 365 日 |
| `system.billing.list_prices` | ある期間の SKU 単価 1 件 | `sku_name` / `currency_code` / `price_start_time` / `price_end_time` / `pricing` | 無期限 |
`usage_metadata` は構造体で、`cluster_id`、`job_id`、`job_run_id`、`warehouse_id`、`dlt_pipeline_id`、`node_type` などを持ちます。誰の実行かは `identity_metadata.run_as` です。`pricing` も構造体で、`default` が長期見積り用の定価、`promotional` が期間限定の割引価格、`effective_list` がその時点で実際に適用される実効定価です。ここに載るのは公開定価であり、個別の契約割引は反映されません。
もう一つの落とし穴が `record_type` です。値は `ORIGINAL`、`RETRACTION`、`RESTATEMENT` の 3 種類で、後から訂正が入ると、元の行を打ち消す負の数量の `RETRACTION` 行と、訂正後の `RESTATEMENT` 行が追加されます。したがって全種別をそのまま合計するのが正しい読み方で、`record_type = 'ORIGINAL'` だけに絞ると訂正が反映されず過大に数えます。
実務での確認手順も押さえます。日次の DBU 消費を見たいなら `usage_date` で集計して AI/BI ダッシュボードに載せ、しきい値超過はアラートにします。Serverless を含むすべてのワークロードがこのテーブルに載るのに対し、Spark UI から DBU を読み取る方法はなく、Serverless では計算ノード自体が見えません。クラスタイベント API を定期的に叩く運用も課金用の情報源ではありません。金額に関する問いはまず `system.billing` を見ると決めておくと迷いません。タグ設計とチャージバックの手順は記事「Databricks コストアトリビューション実務」(`/articles/databricks/cost-attribution/`) に譲ります。
確認 — 穴あけ 3 問
0 / 3
空欄を押すと選択肢が出ます。間違えても減点はありません。
DBU は 1 時間あたりの処理能力を表す単位で、課金は 単位で行われる。
system.billing.usage の使用量を金額に換算するには と結合する。
使用量レコードの record_type は ORIGINAL、RESTATEMENT、 の 3 種類である。
「先月いちばんお金を使ったジョブはどれですか」。よく来る質問ですが、`system.billing.usage` だけでは答えられません。入っているのは SKU と ID だけで、ジョブ名も成否もないからです。実行の側は `system.lakeflow` スキーマにあります。
| テーブル | 1 行の意味 | 型 |
|---|---|---|
| `system.lakeflow.jobs` | ジョブ定義 1 世代 | SCD2 |
| `system.lakeflow.job_tasks` | タスク定義 1 世代 | SCD2 |
| `system.lakeflow.job_run_timeline` | run の時間スライス | 追記のみ |
| `system.lakeflow.job_task_run_timeline` | タスク run の時間スライス | 追記のみ |
`job_run_timeline` は run ごとに 1 行ではありません。1 時間を超える run は複数行に分割されます。注意点が二つ出ます。行数をそのまま実行回数として数えると水増しになること、そして `result_state` と `termination_code` は run の最後の行にだけ入り、途中のスライスは `NULL` になることです。`result_state` の値は `SUCCEEDED`、`FAILED`、`SKIPPED`、`CANCELLED`、`TIMED_OUT`、`ERROR`、`BLOCKED` です。
所要時間の列には但し書きが要ります。`setup_duration_seconds`、`queue_duration_seconds`、`execution_duration_seconds` などの 5 列はレガシー Jobs API で作られた単一タスクジョブでしか埋まりません。現行のマルチタスクジョブでは 0 が並ぶため、遅さの内訳をここで切り分けようとしても数字は出ません。
結合は 2 段です。まず使用量を `usage_metadata.job_id` と `job_run_id` で run 単位に集計し、次に `job_run_timeline` を `workspace_id` と `job_id` と `run_id` で突き合わせます。金額まで出すなら三段目に `list_prices` を `sku_name` と `price_start_time` / `price_end_time` の期間で結合します。
WITH j AS (
SELECT workspace_id,
usage_metadata.job_id AS job_id,
usage_metadata.job_run_id AS run_id,
SUM(usage_quantity) AS dbus
FROM system.billing.usage
WHERE usage_metadata.job_id IS NOT NULL
AND usage_date >= current_date() - INTERVAL 30 DAYS
GROUP BY ALL
)
SELECT j.*, MAX(t.result_state) AS result_state
FROM j LEFT JOIN system.lakeflow.job_run_timeline t
USING (workspace_id, job_id, run_id)
GROUP BY ALL ORDER BY dbus DESC;効くのはジョブとして実行した分だけです。`usage_metadata.job_id` が埋まるのはジョブコンピュートかサーバーレスの場合に限られ、汎用クラスタで手回ししたノートブックには付きません。チーム別に割るならタグを付けて `custom_tags` で集計します。SQL ウェアハウスは `warehouse_id`、宣言的パイプラインは `dlt_pipeline_id` が軸です。
前提です。system テーブルは Unity Catalog 有効なワークスペースが条件で、有効化はアカウント管理者が行います。ジョブ側に `dbutils.system.enable()` を書く必要はなく、その API は存在しません。計算資源側は `system.compute.clusters` と `system.compute.node_timeline` で見え、後者だけ保持が 90 日です。テーブル一覧と有効化手順は記事「System Tables とは?」(`/articles/databricks/system-tables/`) に譲ります。
確認 — 穴あけ 3 問
0 / 3
空欄を押すと選択肢が出ます。間違えても減点はありません。
job_run_timeline では を超える run が複数行に分割される。
DBU をジョブ実行へ按分する結合キーは workspace_id と job_id と である。
job_run_timeline の duration 列が値を持つのは、 で作られた単一タスクジョブだけである。
障害連絡で一番時間を溶かすのは、原因の解析ではなく「どこを開くか」で迷う最初の数分です。Databricks は記録の層がいくつもあり、層を間違えると何も書かれていないログを読み続けることになります。症状から入口を引ける表を 1 枚持っておくと、復旧時間が縮みます。
| 症状 | 最初に開く場所 | そこで分かること |
|---|---|---|
| セルが実行前に赤くなる | ノートブックのエラー行ハイライト | インデントやコロンなどの構文エラー |
| 変数の中身が想定と違う | Variable Explorer と組込デバッガ | 変数の値・型・DataFrame のスキーマ |
| クラスタが起動しない | コンピュートの Event log → Driver logs | 終了理由と init script の `stderr` |
| ジョブのタスクが例外で終了 | Run 画面のタスク出力 | スタックトレースと再実行対象 |
| パイプラインの行数が合わない | イベントログと Data Quality タブ | Expectations 違反と除外された行数 |
| SQL が遅い・0 行になる | Query History とクエリプロファイル | フェーズ別時間と読み取り行数 |
| 特定タスクだけ極端に長い | Spark UI の Stages / Tasks | シャッフル量・スピル・時間の偏り |
ロジックの誤りは、ログを読むより止めて見るほうが速いです。ノートブックには対話的なデバッガが組み込まれています。対象は Python セルのみで、サーバーレスコンピュート、標準アクセスモードなら Databricks Runtime 14.3 LTS 以上、専用アクセスモードなら 13.3 LTS 以上が要件です。セル左端のガターをクリックしてブレークポイントを置き、ステップ実行とステップインができます。停止中はデバッグコンソールで Python を実行できますが、15 秒でタイムアウトします。
できないことも整理します。Python ライブラリの内部や他のノートブックへはステップインできません。デバッグコンソールで `display()` は使えず、`df.show()` で代用します。そしてローカル PC の `pdb` に attach する構成は取れません。コードはマネージドクラスタのドライバ上で動くためです。手元の IDE から書くなら Databricks Connect を使い、実行はクラスタ側に残します。
Variable Explorer は右側のパネルで、現在のセッションの変数を名前・型・サイズ・値のプレビュー付きで一覧します。Python かつ DBR 12.2 LTS 以上ならセルの実行中に随時更新され、Scala と R、DBR 11.3 LTS 以下の Python ではセルが終わってから更新されます。表示範囲はアタッチ中のノートブックのセッションに閉じています。
| ログ | 付いている対象 | 見方 | 保持 |
|---|---|---|---|
| イベントログ | 宣言的パイプライン | UI の Event log タブ / `event_log()` | パイプラインに紐付く |
| ドライバログ | コンピュート (クラスタ) | コンピュート詳細の Driver logs | ログ配信を設定すれば永続 |
| Query History | SQL の文 1 本 | Query History UI / `system.query.history` | システムテーブルは 365 日 |
| Spark UI | Spark のジョブとタスク | コンピュート詳細の Spark UI | クラスタの生存期間 |
宣言的パイプラインや Lakeflow Connect のインジェストパイプラインの失敗は、イベントログとドライバログが一次調査です。イベントログは `event_log(TABLE(main.sales.my_mv))` または `event_log(<pipelineId>)` というテーブル値関数で SQL から読めます。返る列は `timestamp`、`message`、`level`、`error`、`details`、`event_type` などです。`level` は `INFO`、`WARN`、`ERROR`、`METRICS` の 4 値で、`details` は JSON 文字列です。この関数を呼べるのは対象のストリーミングテーブルまたはマテリアライズドビューの所有者だけです。
ストリーミングテーブルに行が来ない、件数が合わないという症状の定番は、Expectations による除外です。`event_type = 'flow_progress'` に絞り、`details` の `data_quality` に入る `dropped_records` と、期待値ごとの合否件数を確認します。同じ内容は UI の Data Quality タブにも出ます。`ON VIOLATION DROP ROW` で落ちたのか quarantine で別テーブルへ逃げたのかを、ここで一次切り分けします。
ドライバログには `stdout`、`stderr`、`log4j` の出力が集まります。init script が exit code 0 以外で終わるとクラスタは `INIT_SCRIPT_FAILURE` になるので、Event log タブで終了理由を見てから Driver logs の `stderr` を読みます。クラスタを終了すると辿れなくなるため、残すならログ配信を設定します。配信は 5 分ごと、アーカイブは 1 時間ごとで、宛先には Unity Catalog のボリューム (推奨)、S3、DBFS を選べ、`cluster_id` と同名のサブフォルダに書き出されます。
Query History は SQL の文 1 本ごとの記録です。`statement_id`、`statement_text`、`execution_status` に加え、`total_duration_ms` を `compilation_duration_ms`、`execution_duration_ms`、`result_fetch_duration_ms` に分解した内訳と、`read_rows`、`produced_rows` を持ちます。`compute` 構造体の `type` は `WAREHOUSE` か `SERVERLESS_COMPUTE` で、汎用クラスタのクエリは対象外です。長期の分析はシステムテーブル側 (`system.query.history`、365 日) を使います。第 1 節の `statement_id` がここへの外部キーで、リネージから実行本文まで辿れます。
Spark UI は分散実行の内側を見る画面で、Jobs、Stages、Executors のタブがあります。タスク一覧で最大時間と中央値が桁違いなら偏り、Shuffle Read が突出していれば結合の見直し、Spill が出ていればメモリ不足と読みます。構文エラーのように Spark ジョブが起動する前に失敗した場合、Spark UI には何も残りません。
ここまでが後から確認する道具の見取り図です。クエリ履歴からの性能改善の手順は記事「Databricks SQL のクエリ履歴」(`/articles/databricks/dbsql-query-history/`) に譲ります。
確認 — 穴あけ 3 問
0 / 3
空欄を押すと選択肢が出ます。間違えても減点はありません。
ノートブックの組込デバッガが対応する言語は のみである。
宣言的パイプラインのイベントログを SQL から読むテーブル値関数は である。
クエリ履歴を長期に分析するときは、無償保持が 日の system.query.history を使う。
この章のまとめ
この端末にだけ保存されます(登録不要)
この章の根拠
最終確認 2026-08-09 / 対応バージョン DEA 2026-05-04 改訂版
コース全体