Skip to content

Commit 74bdab3

Browse files
Claudelukekim
authored andcommitted
docs(enterprise): clarify which execution mode distributes query work
Synchronous /v1/sql and FlightSQL queries fan out scans to executors but run the rest of the plan on the scheduler. Only asynchronous /v1/queries submissions are split into Ballista query stages and executed across executors. Document the distinction, note the spice query CLI, and record the 503 returned when state_location is unconfigured.
1 parent ab160f8 commit 74bdab3

1 file changed

Lines changed: 18 additions & 6 deletions

File tree

enterprise/features/distributed-query.md

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ The scheduler runs a `PartitionAssignmentTask` on `partition_assignment_interval
181181

182182
### Partition-aware query planning
183183

184-
The DataFusion analyzer rule `PartitionedTableScanRewrite` (scheduler-only) rewrites every `TableScan` on an accelerated table into a `UNION ALL` over per-executor FlightSQL scans, pushing down the executor's partition filter and any user predicates:
184+
The DataFusion analyzer rule `PartitionedTableScanRewrite` runs on scheduler-role nodes and rewrites every `TableScan` on an accelerated table into a `UNION ALL` over per-executor FlightSQL scans, pushing down the executor's partition filter and any user predicates:
185185

186186
```text
187187
Before:
@@ -202,6 +202,8 @@ Executor selection uses a greedy minimum set-cover algorithm: pick the executor
202202

203203
On executors, the `AcceleratedPartitionProvider` resolves partitions to local `TableProvider`s. Row-level partition predicates are not re-evaluated on executors — each executor only holds its own partitions, so filtering happens by ownership.
204204

205+
This rewrite is how [synchronous](#execution-modes) queries reach executor-resident data. Asynchronous queries do not use it — Ballista distributes their scans natively while planning query stages.
206+
205207
### Broadcast joins for small dimension tables
206208

207209
A join between a partitioned fact table and a small dimension table can be federated only at the scans, in which case every fact row travels up to the scheduler, which repartitions and joins centrally. On a large fact table, that transfer dominates query time.
@@ -300,12 +302,22 @@ Setting `snapshots: bootstrap_only` is recommended on executors when the source
300302

301303
## Execution Modes
302304

303-
| Mode | Endpoint | Notes |
304-
| ---------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
305-
| **Synchronous** | `/v1/sql`, FlightSQL | Client waits for the query to complete and receives results directly. Available in any deployment. |
306-
| **Asynchronous** | `/v1/queries` | Client submits a query and polls a `query_id` for status. Full results are retrieved with pagination via `/v1/queries/{query_id}/results`, or chunk-by-chunk via `/v1/queries/{query_id}/results/chunks/{chunk_index}`. **Cluster (scheduler) mode only.** |
305+
The two modes distribute work differently, and the choice determines whether a query becomes a multi-stage cluster job.
306+
307+
| Mode | Endpoint | How work is distributed | Notes |
308+
| ---------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
309+
| **Synchronous** | `/v1/sql`, FlightSQL | Scan fan-out only. The scheduler plans and runs the query itself, reading each partition from its owning executor over FlightSQL (see [Partition-aware query planning](#partition-aware-query-planning)). No cluster job, no query stages, no shuffles. | Client waits for the query to complete and receives results directly. Available in any deployment. |
310+
| **Asynchronous** | `/v1/queries` | Full stage-based execution. The plan is split into Ballista query stages and dispatched as tasks to executors, which shuffle intermediate results between stages. | Client submits a query and polls a `query_id` for status. Full results are retrieved with pagination via `/v1/queries/{query_id}/results`, or chunk-by-chunk via `/v1/queries/{query_id}/results/chunks/{chunk_index}`. **Cluster (scheduler) mode only.** |
311+
312+
Only asynchronous queries create cluster jobs. A synchronous query against a partitioned accelerated table still reads from executors in parallel, but the joins, aggregations, and sorts above those scans run on the scheduler. Submit workloads whose cost sits above the scan — large joins, wide aggregations, distributed sorts — asynchronously so the cluster executes them across executors.
313+
314+
Submit an async query over HTTP with `POST /v1/queries`, or from the CLI with `spice query`, which submits the query and polls until it completes.
315+
316+
Async queries require `runtime.scheduler.state_location` to be configured. Without it the API returns `503`:
317+
318+
> Async queries API requires distributed mode with `runtime.scheduler.state_location` configured. Start with: `spiced --role scheduler`
307319

308-
Async queries require `runtime.scheduler.state_location` to be configured. Because job state is shared through that object store, an in-flight async query survives the loss of the scheduler that planned it — a surviving scheduler assumes ownership and continues driving it, and the client keeps polling the same `query_id`.
320+
Because job state is shared through that object store, an in-flight async query survives the loss of the scheduler that planned it — a surviving scheduler assumes ownership and continues driving it, and the client keeps polling the same `query_id`.
309321

310322
## Observability
311323

0 commit comments

Comments
 (0)