Skip to content

Detector catalog / SQL plans

PLAN

Oversized broadcast join

A broadcast join ships a table too large to broadcast.

Outcome
SQL plans
Scope
Judged per SQL query
Usual fix
A Spark configuration change
CI gate
No budget flag: gate it with --fail-on-introduced against a baseline

An example finding

Where you see it

Dashboard

The PLAN tag marks it in the action region of the dashboard, among the widgets that rank a fix. How to read it in the findings guide.

Agent (MCP)

An assistant can read this entry with the list_detectors tool and its background with get_finding_documentation. The call and the response below come from a real run of the MCP server.

Call

{
  "tool": "list_detectors",
  "arguments": {
    "type": "overBroadcast"
  }
}

Response

{
  "count": 1,
  "detectors": [
    {
      "type": "overBroadcast",
      "name": "oversized broadcast join",
      "tag": "PLAN",
      "tagSharedWith": [
        "duplicatePlanSubtree",
        "smallFiles",
        "underBroadcast",
        "pythonUdf",
        "nestedLoopJoin",
        "mergeRewrite",
        "unprunedScan",
        "joinKeyCast"
      ],
      "family": "plan",
      "pitch": "A broadcast join ships a table too large to broadcast.",
      "region": "action",
      "scope": "sql",
      "fixEffort": "config",
      "thresholdSummary": "a broadcast over 1 GiB",
      "detectors": [
        {
          "detector": "broadcastSizing",
          "version": 3,
          "thresholds": {
            "broadcastTiers": [
              10485760,
              104857600,
              1073741824
            ],
            "comparisonTiers": [
              10737418240,
              322122547200
            ],
            "overBroadcastBytes": 1073741824,
            "minSmallerSideBytes": 1048576
          }
        }
      ],
      "pages": {
        "catalog": "docs/detectors/overBroadcast.html",
        "guide": "docs/user-guide/understanding-findings.html#plan"
      },
      "tuning": {
        "kind": "shared",
        "anchor": "#bottleneck-broadcast-sizing",
        "path": "docs/tuning-reference/bottleneck-broadcast-sizing.html#bottleneck-broadcast-sizing"
      },
      "gate": null
    }
  ]
}

get_finding_documentation call

{
  "tool": "get_finding_documentation",
  "arguments": {
    "type": "overBroadcast"
  }
}

Its response, with each Markdown body replaced by its length

{
  "type": "overBroadcast",
  "name": "Oversized Broadcast Join",
  "detectionDoc": {
    "tag": "PLAN",
    "title": "Plan advisor",
    "content": "<7876 characters of Markdown>"
  },
  "tuningDoc": {
    "anchor": "#bottleneck-broadcast-sizing",
    "title": "Broadcast Sizing",
    "content": "<4467 characters of Markdown>"
  }
}

CI (CLI)

List this entry from the command line. The output below is a real run of the command. Budgets and exit codes are in the CI guide.

sparkforensics-analyze detectors --type overBroadcast --format md
# Detectors (1)

## SQL plans

| Tag | Type | Scope | Fix | Gate | What it finds |
| --- | --- | --- | --- | --- | --- |
| PLAN | `overBroadcast` | sql | config |  | A broadcast join ships a table too large to broadcast. |

Report only this finding type for a run with --type:

sparkforensics-analyze <event-log> --type overBroadcast --impact critical,warning,info

It has no budget flag. Fail a build on a new one by comparing against a baseline with --fail-on-introduced.

Airflow

The operator has no budget parameter for it. Use fail_on_introduced with a baseline.

check_spark_job = SparkForensicsOperator(
    task_id="check_spark_job",
    log_source=...,
    backend=SubprocessAnalyzeHook(),
    baseline_log_source=...,
    fail_on_introduced="critical",
)

The operator works per run, and its summary counts findings per impact band. See the operator for its parameters.

How it is measured

Thresholds

A broadcast over 1 GiB.

broadcastSizing version 3

ThresholdDefault
broadcastTiers[10485760,104857600,1073741824]
comparisonTiers[10737418240,322122547200]
overBroadcastBytes1073741824
minSmallerSideBytes1048576

Each rule's impact bands and fixed fallbacks are in the threshold tables.

Override a default per run with --thresholds; see Tuning detector thresholds.

Docs