Is your feature request related to a problem or challenge?
While writing the DataFusion 55.0.0 blog post
I wrote up the per-partition TopK window optimization as one of the headline performance improvements of the release — and only then discovered that datafusion.optimizer.enable_window_topn defaults to false, so nobody actually gets it unless they opt in.
We probably shouldn't make a big deal about a feature that is off by default, and I could not find any issue tracking turning it on. So I am filing this issue so we don't forget and we can track what is required to do so in one place rather than scattered across PR review threads.
The story we want to be able to tell
This is the text I had drafted for the 55.0.0 blog post before pulling it, included so it's clear what we're aiming for and so whoever finishes this work can reuse it:
Per-Partition TopK for Window Functions
A common analytics pattern selects the top N rows per group using a window
function:
SELECT * FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY category ORDER BY revenue DESC) AS rn, *
FROM sales
) WHERE rn <= 5;
DataFusion previously sorted the entire input to evaluate the window
function, even though only a handful of rows per partition survive the filter.
DataFusion 55 recognizes this pattern and uses a new PartitionedTopKExec
operator that keeps only the top N rows per partition, dramatically reducing
sorting and memory for high-cardinality inputs. The optimization applies to
ROW_NUMBER and RANK, resolving a feature request first filed in 2023
(#6899).
Thanks to @SubhamSinghal for implementing this feature, with reviews from
@2010YOUY01 and @kosiew. Related PRs: #21479, #22885, #23096
Why it is currently off
datafusion/common/src/config.rs:
|
/// When set to true, the optimizer will replace |
|
/// Filter(rn<=K) → Window(ROW_NUMBER) → Sort patterns with a |
|
/// PartitionedTopKExec that maintains per-partition heaps, avoiding |
|
/// a full sort of the input. |
|
/// When the window partition key has low cardinality, enabling this optimization |
|
/// can improve performance. However, for high cardinality keys, it may |
|
/// cause regressions in both memory usage and runtime. |
|
pub enable_window_topn: bool, default = false |
The default was set to false in #21479 because of severe high-cardinality regressions against the plain-sort baseline:
If it has regressions as large as 0.03x it should [be] off by default (and
we should look if we can automatically enable it via a heuristic / stats based
on partition cardinality / rows)
— @Dandandan, #21479 (comment)
#23096 (in 55.0.0) closed most of that gap by sharing the encoder and memory
reservation across partitions:
| Partitions |
main |
with #23096 |
vs sort baseline |
| 100 |
110 ms |
105 ms |
~1.0x |
| 1,000 |
117 ms |
110 ms |
~1.0x |
| 10,000 |
640 ms |
137 ms |
1.7x faster than sort (was a regression) |
| 100,000 |
4,327 ms |
320 ms |
320 ms vs 238 ms — still slower |
but explicitly did not flip the default:
enable_window_topn default stays false per the #21479 discussion — 100K+
remains slower than sort on average, so this PR doesn't motivate flipping the
default. It's the prerequisite for further optimizations that would attack the
residual 100K+ cliff.
— #23096
Describe the solution you'd like
Set enable_window_topn to true by default, once we are confident it does not
regress. Known work items:
Describe alternatives you've considered
Leave it opt-in indefinitely. 👎 -- an optimization nobody turns on is close to an optimization that doesn't exist
Additional context
Is your feature request related to a problem or challenge?
While writing the DataFusion 55.0.0 blog post
55.0.0release #24216I wrote up the per-partition TopK window optimization as one of the headline performance improvements of the release — and only then discovered that
datafusion.optimizer.enable_window_topndefaults tofalse, so nobody actually gets it unless they opt in.We probably shouldn't make a big deal about a feature that is off by default, and I could not find any issue tracking turning it on. So I am filing this issue so we don't forget and we can track what is required to do so in one place rather than scattered across PR review threads.
The story we want to be able to tell
This is the text I had drafted for the 55.0.0 blog post before pulling it, included so it's clear what we're aiming for and so whoever finishes this work can reuse it:
Why it is currently off
datafusion/common/src/config.rs:datafusion/datafusion/common/src/config.rs
Lines 1574 to 1581 in fdf7935
The default was set to
falsein #21479 because of severe high-cardinality regressions against the plain-sort baseline:#23096 (in 55.0.0) closed most of that gap by sharing the encoder and memory
reservation across partitions:
mainbut explicitly did not flip the default:
Describe the solution you'd like
Set
enable_window_topntotrueby default, once we are confident it does notregress. Known work items:
metrics()returnsNone) #24470 / fix: expose PartitionedTopKExec metrics #24495dense_rankbenchmark; we should make sure the sweep covers high partition-cardinality as welldocs/source/user-guide/configs.md.Describe alternatives you've considered
Leave it opt-in indefinitely. 👎 -- an optimization nobody turns on is close to an optimization that doesn't exist
Additional context
WHERE rn < 1) was fixed in fix: skip WindowTopN rewrite when fetch is 0 to avoid PartitionedTopK panic #24405, but that landed after thebranch-55cutROW_NUMBER < 5/ TopK #6899 (original 2023 request),metrics()returnsNone) #24470, fix: reduce RANK window top-K memory from O(input) to O(K + ties) per partition #24591.