datafusion-contrib / datafusion-contrib/datafusion-distributed

[Epic][part 2] Adaptive Query Execution, runtime plan optimization

Open
#522 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
139
Forks
67
Avg merge
3d 1h
Merged PRs (30d)
35

Description

Follow-up to #377.

#377 laid the foundation for Adaptive Query Execution: stages are now planned dynamically, and runtime statistics gathered by the SamplerExec are used to make decisions like the number of tasks assigned to each stage (see #432).

Now that accurate runtime statistics flow through the coordinator as stages execute, the next step is to re-optimize the not-yet-executed stages on the fly based on those stats, rather than only sizing tasks. For example:

  • Swapping join orders based on observed cardinalities.
  • Switching join implementations (e.g. broadcast vs shuffle) once the build-side size is known (relates to the broadcast_joins follow-up).
  • Coalescing/splitting partitions to handle data skew discovered at runtime.
  • Other physical optimizations that become possible once real stats replace planning-time estimates.

Early exploration lives on the gabrielmusat/aqe branch.

Prior art

This kind of execution-time replanning is well established in other distributed engines. Their designs are a good reference for what it unlocks and how it's delivered:

Apache Spark — Adaptive Query Execution (AQE) (enabled by default since 3.2). At each shuffle stage boundary, Spark re-runs the optimizer with statistics from completed stages. Three headline optimizations:

Trino — Adaptive plan optimizations (since Trino 457, requires fault-tolerant execution). Because intermediate exchange data is spooled, Trino can reorder partitioned joins based on the actual build/probe sizes observed mid-query, rather than pre-computed connector statistics.

A recurring theme across both: a materialization/exchange boundary is what makes safe replanning possible, and join strategy/order + partition sizing are the highest-value decisions to defer to runtime — which maps directly onto the stage boundaries this project already has.

This work will be broken down into independently contributable sub-issues:

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the foundation in #377, the runtime statistics flow through SamplerExec and the coordinator, and the exploration on the gabrielmusat/aqe branch. Use the Spark and Trino references to narrow this epic into a concrete sub-issue, then check #641 for the planned breakdown. Done should be defined by an independently contributable runtime re-optimization task with explicit behavior and validation.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
distributed-systems
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.