PostgreSQL EXPLAIN Plan Analyzer
Inspect PostgreSQL EXPLAIN plans for costly nodes and row-estimate drift with browser-local parsing of scan, spill and buffer clues.| Depth | Node | Target | Cost | Rows | Actual | Signals | Copy |
|---|---|---|---|---|---|---|---|
| No plan nodes are available. | |||||||
| {{ row.depth }} | {{ row.node }} | {{ row.target }} | {{ row.cost }} | {{ row.rows }} | {{ row.actual }} | {{ row.signals }} | |
| Severity | Signal | Evidence | Next action | Copy |
|---|---|---|---|---|
| No findings match the selected display filter. | ||||
| {{ row.severity }} | {{ row.signal }} | {{ row.evidence }} | {{ row.action }} | |
No positive planner cost values to plot.
No actual row counts to compare. Supply an EXPLAIN ANALYZE plan for row drift.
Query tuning begins with the work PostgreSQL chose, not with the SQL text alone. An execution plan is a tree of scans, joins, sorts, aggregates, and other nodes. Indented children feed their parents, so an expensive line must be understood together with how often it runs and how many rows it passes upward.
| Value | What it describes | Important limit |
|---|---|---|
cost=a..b |
Estimated startup and total work in planner units | Cost is not elapsed time |
rows=n |
Estimated rows emitted by a node | It does not count every row inspected |
actual time=a..b |
Measured startup and total time per loop | Loop count changes the total work |
Buffers |
Shared and temporary block activity | Cache hits and storage reads are different evidence |
Plain EXPLAIN shows estimates derived from statistics, indexes, configuration, and planner assumptions. EXPLAIN ANALYZE executes the statement and adds actual rows, timing, and loops. Buffer reporting, sort-disk use, and hash batches can expose I/O or spill behavior that estimates alone cannot show.
A sequential scan is not automatically inefficient. It can be the cheapest path when a query needs much of a table, while an index scan can become costly when it returns many rows or repeats inside a nested loop. Likewise, a large estimate error is a clue about statistics, data skew, correlated predicates, or parameters rather than proof that a particular index is missing.
Plans describe one query, parameter set, schema, statistics snapshot, configuration, and data distribution. Compare before-and-after plans under equivalent conditions. Warning thresholds can prioritize review, but they cannot decide whether the workload is acceptable.
How to Use This Tool:
Capture a complete plan with its indentation or machine-readable structure intact, then choose thresholds that are meaningful for the same database and workload.
- Paste or load the plan. Text, JSON, and XML are accepted up to 200,000 characters. Auto detect treats an opening
<as XML,{or[as JSON, and other content as text. - Pin Input format when needed. A copied wrapper or leading text can mislead automatic selection; the chosen parser must find at least one plan node with cost estimates.
- Set the warning values. Cost warning evaluates estimated total cost, Row drift warning compares estimated and actual rows, and Sequential scan warning uses the larger of estimated or actual emitted rows. Equality triggers all three floors.
- Inspect node evidence before acting on a finding. Check tree depth, relation or index, cost, rows, loops, spill signals, and buffer activity around the flagged node.
- Narrow Finding display only for review. The display filter hides lower-severity rows but leaves the parsed plan and the warning and critical counts unchanged.
Interpreting Results:
Critical review means at least one high-cost or row-drift rule crossed its critical multiple. Review signals means one or more warnings were found. Baseline captured means no warning or critical rule fired under the current settings. These statuses summarize a review policy, not query correctness.
- Compare planner cost only within a consistent planner environment; do not read it as milliseconds.
- Investigate row drift where it changes join choice, scan size, or repeated work, then check statistics and representative parameter values.
- Treat disk sorts, multiple hash batches, and temporary blocks as spill clues. Confirm the input size and concurrent memory pressure before changing
work_mem. - An estimate-only plan cannot confirm runtime. Collect actual evidence only when executing the statement is safe.
Technical Details:
Text plans encode hierarchy through indentation and attach details on following lines. JSON and XML carry explicit child collections and named metrics. Each path is flattened into node order while retaining depth, relation or index names, estimates, actual measurements, buffer counts, sort-disk use, hash batches, and removed rows where those values are present.
Transformation Core:
| Format | Tree rule | Evidence read |
|---|---|---|
| Text | Recognized node lines and leading spaces establish depth. | Costs, rows, actual timing, loops, buffers, sort disk, hash batches, and removed rows |
| JSON | A top-level Plan object is traversed through its child plans. |
Named numeric fields from each node |
| XML | The first Plan element is traversed through nested plan elements. |
Equivalent named elements where present |
YAML output is not accepted. Text parsing also depends on recognizable PostgreSQL node lines, so altered labels or heavily reformatted plans may fail even if a person can still read them.
Formula Core:
Row drift is symmetric: a tenfold underestimate and a tenfold overestimate both produce a magnitude of 10. Each row count is floored at 1 before division so zero-row nodes remain finite.
Actual rows at least as large as estimated rows are labelled underestimated; smaller actual values are labelled overestimated. A document-level execution time takes precedence. When it is absent, the root node's total time is multiplied by at least one loop. Planner cost is never converted into time.
Rule Core:
| Finding | Warning | Critical |
|---|---|---|
| Highest total cost | >= cost warning | >= 5 × max(1, cost warning) |
| Row estimate drift | >= row drift warning | >= 10 × row drift warning |
| Large sequential scan | Estimated or actual rows >= scan warning | None |
| Disk-backed sort | Sort disk > 0 KiB | None |
| Hash batching | Batches > 1 | None |
| Temporary I/O | Temp reads + writes > 0 blocks | None |
An estimate-only plan always receives an informational finding. If no configured cost, scan, spill, or drift condition fires, a baseline informational row keeps the finding set non-empty.
Safety and Privacy Notes:
Plan text and loaded files are parsed in the browser. Plans can expose schema names, table and index names, predicates, literal values, and workload shape, so remove secrets and personal data before sharing the plan or its results.
EXPLAIN ANALYZE executes the statement. A transaction followed by ROLLBACK can revert ordinary table changes, but it cannot undo every side effect, including sequence increments or external calls. Use a safe environment for data-changing or expensive statements.
References:
- Using EXPLAIN, PostgreSQL Global Development Group, PostgreSQL 18 documentation.
- EXPLAIN command reference, PostgreSQL Global Development Group, PostgreSQL 18 documentation.
- ANALYZE command reference, PostgreSQL Global Development Group, PostgreSQL 18 documentation.
- How to explain a query plan in PostgreSQL, Simplified Guide.