Reading execution plans#
Querona returns SQL Server–compatible execution plans, so the plan tools you already use — SQL Server Management Studio’s Display Estimated Execution Plan (Ctrl+L) and Include Actual Execution Plan (Ctrl+M) — work against Querona and render a graphical plan. Because Querona is a federation engine, that plan answers the two questions that matter most when a federated query is slow: what was pushed down to which source (and as what SQL), and what did the engine have to do itself.
What a plan shows#
A Querona plan is a tree of operators, read from the leaves up. Each leaf is one of two things:
a Remote Query operator — a query pushed down to a single source; or
a local scan of data already held by the engine.
Everything above the leaves is work Querona performs itself — joining, sorting, aggregating and filtering the partial results that come back from the sources. Consider a query that joins a table in one source with a table in another:
SELECT c.name, SUM(o.total) AS lifetime_value
FROM crm.dbo.customers AS c -- e.g. a SQL Server source
JOIN sales.public.orders AS o -- e.g. a PostgreSQL source
ON o.customer_id = c.id
WHERE c.region = 'EU'
GROUP BY c.name;
Neither side’s data lives in Querona, and the join crosses two sources, so it cannot be pushed to either source alone. The plan shows each side retrieved through its own Remote Query leaf — each already filtered and projected by push-down — brought together by an in-memory join, then aggregated and sorted by the engine:
flowchart BT
RQA["Remote Query — crm (SQL Server)"]
RQB["Remote Query — sales (PostgreSQL)"]
NL["Nested Loops (join)"]
AGG["Stream Aggregate (SUM, GROUP BY)"]
SORT["Sort"]
RQA --> NL
RQB --> NL
NL --> AGG
AGG --> SORT
The operators use standard SQL Server names (such as Remote Query, Nested Loops,
Hash Match, Sort, Stream Aggregate, Filter and Compute Scalar), so third-party
plan viewers and community tooling read them the same way they read a SQL Server plan.
Remote Query — the push-down boundary#
The Remote Query operator is the single most useful thing in a Querona plan: it marks the
boundary between what ran at a source and what ran in the engine. Select a Remote Query operator
and its properties show:
the source the query was sent to, and
the exact SQL text Querona generated for that source.
That text is the primary tuning signal. Reading it answers the questions that decide a federated query’s cost:
Was the
WHEREclause pushed down? If the filter appears in the remote SQL, the source discards rows before they cross the network. If it does not, Querona pulled the rows back and filtered them itself — usually the thing to fix.Was a whole join shipped to one source? When both joined tables live in the same source, the join should appear inside a single
Remote Queryrather than as two leaves under an in-memory join.How much work is each source doing? Aggregation, sorting and row limits that show up in the remote SQL are work the source did, so only the reduced result travelled back.
For the mechanics of what Querona pushes down and why, see Federation.
Estimated plans and actual plans#
Querona supports both plan kinds SQL Server does, through the same gestures and the same underlying
SET statements.
Display Estimated Execution Plan (Ctrl+L) — compiles the query and shows the plan without running it. Nothing executes; you see the shape and the pushed-down SQL before paying to run anything.
Include Actual Execution Plan (Ctrl+M) — runs the query and shows the plan next to the results, with run-time counters (actual row counts, elapsed time).
Estimated plans: SET SHOWPLAN_XML (the XML SSMS renders), SET SHOWPLAN_TEXT and SET SHOWPLAN_ALL. Turning one on freezes the session — statements are compiled, not executed — until you turn it off.
Actual plans: SET STATISTICS XML (Ctrl+M’s XML) and SET STATISTICS PROFILE. Statements execute normally and each one’s plan follows its results.
How to read the numbers#
Querona reports honest plans: it has no optimizer cost model, so rather than filling the cost and row-count figures with plausible-looking placeholders, it reports only what it genuinely knows and marks the rest as not modeled.
What you can rely on — the parts of a plan that carry real information:
The operator tree — its shape (read leaves-up) and each operator’s type.
Remote Query properties — the source each sub-query was sent to and the exact SQL Querona generated for it, including which predicates and columns were pushed down. This is the primary tuning signal (see the previous section).
The logical detail on each operator — filter and join predicates,
ORDER BYandGROUP BYkeys, the output column list, aggregate defined values, and the set-operator kind (UNION/INTERSECT/EXCEPT).In an actual plan (Ctrl+M) — the root operator’s row count (the rows actually returned to the client) and the query’s elapsed time.
The values it does not model — reported as a fixed value rather than a fabricated estimate:
Costs are always 0.
EstimateIO,EstimateCPUand the subtree costs are always0— Querona has no cost-based optimizer, so there is nothing to estimate. A plan viewer’s per-operator Cost % (SSMS included) is calculated from these same zeros, so do not read it as meaningful.Row estimates are not modeled.
EstimateRowsis a fixed placeholder (1) on every operator, not a per-operator cardinality estimate — treat it as “not modeled”, never as a prediction.In an actual plan, only the root operator’s row count is real — it is the number of rows actually returned to the client. Interior operators carry no run-time row count at all (SSMS shows no Actual Number of Rows for them, and the underlying XML has no
RunTimeInformationfor that operator).CpuTimeis always 0 in actual plans; there is no per-statement CPU accounting.DegreeOfParallelismis always 0; Querona does not produce parallel plan shapes.
None of this affects the plan’s structure or the Remote Query pushdown text — those are real, and are what the previous section tells you to trust.
Differences from SQL Server#
Execution plans are wire-compatible with SQL Server and render in the same tools, with these differences to keep in mind:
No SHOWPLAN permission. SQL Server gates plan output behind a separate SHOWPLAN permission; Querona does not — any authenticated session can request a plan. This is simpler to use, but it is a behavioural difference: a permission SQL Server enforces is not enforced here.
CpuTimeis always 0, and in an actual plan only the root operator carries a run-time row count at all — interior operators show none (see above).No parallel plans.
DegreeOfParallelismis always 0 and plans never take a parallel shape.SET STATISTICS TIME and SET STATISTICS IO are not part of the plan surface. In SQL Server they report timing and I/O messages; Querona accepts the statements but they have no effect.