CertSafari
    Databricks Certified Data Engineer Professional - October 9 onwards· Lessons

    Domain 4 · Lesson 22/46

    Auditing and Job Monitoring with system.access.audit and system.lakeflow

    Use Databricks system tables (billing, compute, access, lakeflow) for cost analysis, auditing, and workload monitoring.

    10 min read
    2% of exam
    3 sources
    Published 3 Oct 2026
    Docs as of 30 Sep 2026

    What you will be able to do

    • Query system.access.audit to answer who-did-what questions, and explain its regional scope and masked parameters
    • Name the six system.lakeflow tables and say which are SCD2 dimension tables and which are immutable timelines
    • Write a query that returns the current state of jobs or tasks, excluding deleted ones, from an SCD2 table
    • Use the run timeline tables to monitor run outcomes and the compute each task used

    1.Auditing account activity with system.access.audit

    Billing tells you what was spent. system.access.audit tells you who did what. The table is in Public Preview and records audit events from the workspaces in your region. Each row is one event, made up of the service that handled it, the action, the person or principal who called it, the parameters they sent and the response they got.

    Core columns of system.access.audit
    ColumnMeaningExample
    event_dateCalendar date of the action; filter on this for performance2023-01-01
    event_timeTimestamp of the event (UTC)2023-01-01T01:01:01.123+00:00
    user_identityIdentity of user initiating request{"email": "user@domain.com", "subjectName": null}
    service_nameService name initiating requestunityCatalog
    action_nameCategory of the event captured in audit loggetTable
    request_paramsMap of all the request parametersfull_name_arg, workspace_id, metastore_id
    responseStruct of response return values{"statusCode": 200, "errorMessage": null, "result": null}
    audit_levelWorkspace or account level eventACCOUNT_LEVEL
    source_ip_addressIP address where the request originated10.30.0.242

    Four details affect how you query it:

    - Partition by date. Filter on event_date, not event_time, to improve query performance. - Scope. Workspace-level events are regional. Account-level events are global and record workspace_id as 0, so an account-level action won't show up under a workspace ID filter. - Masking. Some events store SQL definitions in request_params under keys such as view_definition and function_info. Those keys are omitted unless you are an account admin or a member of the databricks_pii_access group. Other keys and columns are unchanged. - Workspace deletion. When a workspace is deleted, its audit events older than 14 days are removed from the table, so export anything you must keep before decommissioning a workspace.

    Checkpoint 1 of 7· Check yourself

    An auditor filters system.access.audit on a specific workspace_id and can't find an account-level administrative action they know took place. Why?

    Checkpoint 2 of 7· Exam question

    A security team suspects that a service principal exported large tables outside normal business hours. They plan to investigate using `system.access.audit`, which records `event_time`, `service_name`, `action_name`, `user_identity`, `request_params`, `response`, and `audit_level` for every logged event. Which two filters should they combine to surface the suspicious export events? (Choose two)(Select 2)

    Sources1

    2.The system.lakeflow schema: jobs, tasks, pipelines and their timelines

    For workload monitoring, the main schema is system.lakeflow, which was previously called workflow. Both schemas have identical content, so older queries against system.workflow still match. The tables are regional: to see another region's jobs, you query from a workspace deployed in that region. Job tables typically get records within one hour, which is much fresher than billing data.

    The six tables in system.lakeflow
    TableTracksKind
    jobsAll jobs created in the accountSCD2 (key: workspace_id, job_id)
    job_tasksAll job tasks that run in the accountSCD2 (key: workspace_id, job_id, task_key)
    job_run_timelineJob runs and related metadataImmutable
    job_task_run_timelineJob task runs and related metadataImmutable
    pipelines (Public Preview)All pipelines created in the accountSCD2 (key: workspace_id, pipeline_id)
    pipeline_update_timeline (Public Preview)Pipeline updates and related metadataImmutable

    Checkpoint 3 of 7· Check yourself

    Which of these system.lakeflow tables is an immutable timeline that needs no deduplication?

    The jobs table also stores the definition fields you'll want to audit, including run_as_user_name, creator_user_name, paused, timeout_seconds, health_rules and trigger_type (MULTIPLE when a job has several triggers). Many of these columns aren't populated for rows emitted before early December 2025, so null values in older history are expected and don't mean the data is bad.

    Sources2

    3.Querying current state from SCD2 tables

    jobs, job_tasks and pipelines never update a row. Each change adds a new row with a new change_time, and a deletion adds a row with delete_time populated. A plain SELECT * FROM system.lakeflow.jobs therefore returns every historical version of every job. To get current state, take the latest row per entity key, and only after that drop rows that record a deletion.

    Current state of every job, excluding deleted jobssql
    -- Get the current state of every job, excluding deleted jobs
    with latest AS (
      SELECT
        *,
        ROW_NUMBER() OVER(PARTITION BY workspace_id, job_id ORDER BY change_time DESC) as rn
      FROM
        system.lakeflow.jobs QUALIFY rn=1
    )
    SELECT * FROM latest WHERE delete_time IS NULL

    Checkpoint 4 of 7· Put it in order

    Put the steps for getting the current, non-deleted state of entities from an SCD2 table in order

    1. 1.Exclude rows where delete_time is populated
    2. 2.Partition rows by the table's entity key (e.g. workspace_id, job_id)
    3. 3.Order each partition by change_time descending and keep only the first row

    Checkpoint 5 of 7· Fill the gap

    job_tasks is keyed below the job level. Which column completes the partition key?

    -- Get the most recent version of each job task
    SELECT
      *,
      ROW_NUMBER() OVER(PARTITION BY workspace_id, job_id,  ?  ORDER BY change_time DESC) as rn
    FROM
      system.lakeflow.job_tasks QUALIFY rn=1

    Checkpoint 6 of 7· Exam question

    Monthly compute spend has spiked. An engineer joins `system.compute.clusters` to `system.billing.usage` and finds several all-purpose clusters with `autotermination_minutes = 0` running continuously under a shared `owned_by` service principal that no longer maps to an active team. What is the most effective first remediation based on this system table data?

    Sources2

    4.Monitoring runs with the timeline tables

    The timeline tables record what actually ran. job_run_timeline, job_task_run_timeline and pipeline_update_timeline are immutable and complete when produced, so they need no deduplication. Long runs are split into hourly slices across several rows, each bounded by period_start_time and period_end_time, and availability is measured from period_end_time.

    In job_task_run_timeline, each row carries job_id, job_run_id, run_id (the task run) and task_key. The compute_ids array lists the job clusters, interactive clusters and SQL warehouses the task used, which lets you join a task's runtime to system.compute and, through cluster_id, to its billing rows. Because of hourly slicing, result_state is filled only on the row that represents the end of the run. When you count failures, filter or aggregate on that row; don't count every slice.

    Checkpoint 7 of 7· Check yourself

    A task ran for three hours and failed. In job_task_run_timeline it spans several rows. Where do you find its outcome?

    Sources2

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.Adding WHERE delete_time IS NULL directly to the query that reads system.lakeflow.jobs removes deleted jobs.Why is that wrong?

      Filtering delete_time in the same pass discards the deletion row, so the job's last pre-deletion version is returned as if it were current. Select the latest row first, then filter.

      Covered in Querying current state from SCD2 tables

    2. 2.system.access.audit is global like system.billing.usage, so one query from any workspace sees every region's events.Why is that wrong?

      Audit data is regional for workspace-level events. Only account-level events are global.

      Covered in Auditing account activity with system.access.audit

    Practise it for real

    Build a current-state inventory of jobs and tasks from system.lakeflow and confirm that deleted jobs are excluded

    1. 1.Run SELECT COUNT(*) FROM system.lakeflow.jobs and compare it with the number of jobs you see in the Jobs UI.

      Why: jobs is an SCD2 table, so every edit and deletion adds a row.

      You should see: The count is higher than your number of jobs because the table holds every historical version.

    2. 2.Run the 'current state of every job, excluding deleted jobs' query from this page.

      Why: ROW_NUMBER over workspace_id, job_id ordered by change_time DESC keeps the latest version, and the outer filter removes deleted jobs.

      You should see: One row per live job, matching the jobs you can see.

    3. 3.Move the delete_time IS NULL filter inside the CTE and run the query again.

      Why: This shows the ordering trap: the deletion row is filtered out before the latest row is chosen.

      You should see: Deleted jobs reappear, showing their last state before deletion.

    4. 4.Adapt the query to system.lakeflow.job_tasks, partitioning by workspace_id, job_id, task_key.

      Why: Each SCD2 table has its own entity key.

      You should see: One row per live task per job.

    Stuck? Get a nudge

    If step 3 returns the same rows as step 2, check whether anyone has deleted a job in the last 365 days; without a deletion there's nothing for the trap to expose.

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
      “Table path: This system table is located at system.access.audit.”
      ↩︎ Auditing account activity with system.access.audit
      “To improve query performance, filter on event_date rather than event_time.”
      ↩︎ Auditing account activity with system.access.audit
      “keys in request_params that contain SQL definitions are omitted unless you are an account admin or a member of the databricks_pii_access group”
      ↩︎ Auditing account activity with system.access.audit
      “When you delete a workspace, Databricks removes that workspace's audit events that are older than 14 days from system.access.audit.”
      ↩︎ Auditing account activity with system.access.audit
      “Account-level audit logs record workspace_id as 0.”
      ↩︎ Checkpoint
    2. 2.
      “The lakeflow schema was previously known as workflow. The content of both schemas is identical.”
      ↩︎ The system.lakeflow schema: jobs, tasks, pipelines and their timelines
      “To see records from another region, you must view the tables from a workspace deployed in that region.”
      ↩︎ The system.lakeflow schema: jobs, tasks, pipelines and their timelines
      “records are typically available within one hour.”
      ↩︎ The system.lakeflow schema: jobs, tasks, pipelines and their timelines
      “Deletions are recorded as a new row with delete_time populated, not by removing rows.”
      ↩︎ Querying current state from SCD2 tables
      “job_tasks: workspace_id, job_id, task_key”
      ↩︎ Querying current state from SCD2 tables
      “The job run timeline, job task run timeline, and pipeline update timeline tables are immutable, so they need no deduplication.”
      ↩︎ Monitoring runs with the timeline tables
      “The compute_ids array contains IDs of job clusters, interactive clusters, and SQL warehouses used by the job task”
      ↩︎ Monitoring runs with the timeline tables
      “For the job_run_timeline and job_task_run_timeline tables, availability is measured from the period_end_time column.”
      ↩︎ Monitoring runs with the timeline tables
      “Filtering delete_time in the same query that reads the table returns each deleted entity's last state before deletion instead of omitting the entity.”
      ↩︎ Exam trap 1
      “The job run timeline, job task run timeline, and pipeline update timeline tables are immutable, so they need no deduplication.”
      ↩︎ Checkpoint
      “Databricks retains the most recent record for each entity in the slowly changing dimension (SCD2) tables (jobs, job_tasks, and pipelines).”
      ↩︎ Prediction
      “take the row with the most recent change_time, then exclude the rows that record a deletion”
      ↩︎ Checkpoint
      “this column is populated only in the row that represents the end of the run”
      ↩︎ Checkpoint

    Also cited

    Spotted a mistake, or was something unclear? Tell us.