Inspect query plans and diagnostics
Use the current console guide for live instance workflows and availability. Screenshots below illustrate the demo workspace with sample data. In the signed-in console, actions operate on the selected instance when your role and its capabilities allow them.
Find costly query patterns, inspect their plans, and compare changes from the Workbench.
1. Open Explain from the Workbench
In Workbench ? Editor, select SQL and prepare a query. Open the arrow beside Run, then choose Explain plan or Explain and run. The plan appears in the results area's Query plan tab.
Explain and run executes the query. Use plan-only mode when you only need its structure. Keep exploratory queries bounded while iterating; a LIMIT at the top of a plan does not necessarily prevent work below it.
The local preview displays schematic operators and sample data. Its browser durations are not live engine measurements, and per-operator timings appear only when collected.
2. Read from inputs to output
The operator at the top produces the final result. Follow its inputs down to see how rows are read, filtered, and joined, then read upward to understand the data flow. Select an operator to inspect its details.
| Operator | What to inspect |
|---|---|
| Scan | The table and rows read; on a live plan, inspect any segment-scan or pruning details it reports. |
| Filter | The predicate and how many input rows survive it. |
| Join | The join keys and work performed by each input. |
| Limit | The output cap, while checking how much work happened before it. |
On a live analyzed plan, self time excludes child operators. Compare actual rows, estimated rows, and self time only when the response provides them; an absent value is not zero.
3. Keep plans and execution separate
Explain plan does not execute the query. It can help you inspect the intended operators, but it cannot tell you the actual elapsed time or rows processed. Explain and run executes the query and may return measured values from the connected engine.
4. Find expensive patterns in Query stats
Open the Workbench's Query stats tab. SQL literals are replaced with placeholders so similar executions can be grouped. Start with total time, then compare calls, latency percentiles, and average returned rows.
Select a pattern to inspect it. Open in editor and Explain in editor prepare a new draft; neither runs it. Replace any placeholder values and review the query before execution.
In local preview, the stats use recorded browser activity and optional sample activity. They are not a complete audit log or live telemetry. The classic engine registry is in memory, holds up to 200 fingerprints by total time, and resets on engine restart.
5. Inspect an individual slow execution
Slow queries shows individual executions. Set the duration threshold, inspect a row's query and result details, and reopen it in the editor when you need to reproduce the work. Opening an entry never executes it automatically.
Raw query text can contain sensitive literal values. Live access and masking policies still apply. The engine's recent-execution window is an in-memory ring of up to 200 entries that resets on restart; local preview history is a separate browser record.
6. Change one thing and compare
- If a scan reads many rows that a filter discards, inspect the predicate and available secondary indexes.
- If a join dominates, check its keys and whether each input can be narrowed earlier.
- If you return more rows or columns than the application uses, reduce the projection or result limit.
- If tail latency is high, reproduce a slow execution with its actual parameter values.
Add or change indexes through Data Explorer or the schema API, then compare the same query again. An index is useful only if the resulting plan uses it for the workload.
SQL example and plan shape
These examples illustrate a join and its operator structure. The actual plan depends on the query, schema, and engine version.
SELECT o.id, c.name, c.country, o.amount_cents
FROM shop.orders o
JOIN shop.customers c ON o.customer = c.id
WHERE o.status = 'paid'
LIMIT 10limit(10)
hash_join(on customer = id)
filter(Eq { path: "status", value: String("paid") })
scan(shop.orders)
scan(shop.customers)Continue with the SQL reference for supported query syntax and EXPLAIN behavior.