-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Specialize Primitive Cursor -- make sorts / merges on a single primitive column faster #5897
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| offset: usize, | ||
| // If nulls first, the first non-null index | ||
| // Otherwise, the first null index | ||
| null_threshold: usize, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm quite pleased with this formulation of nulls, it avoids needing to consult the null mask at all 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason it is called null_threshold rather than null_index given it is a null index 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought null_index might be confused for the index of the first null, which is not always the case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that makes sense.
| options: SortOptions, | ||
| } | ||
|
|
||
| impl<T: ArrowNativeTypeOp> PrimitiveCursor<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The astute will notice this is parameterised on the underlying Native type, helping to reduce codegen by not forcing SortPreservingMergeStream to be generic over ArrowPrimitiveType
datafusion/core/Cargo.toml
Outdated
| arrow-schema = { workspace = true } | ||
| arrow-array = { workspace = true } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The downcast macros require these crates to be in scope
5f7a3d6 to
04567b7
Compare
alamb
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @tustvold -- this looks great. cc @jaylmiller and @ozankabak
| offset: usize, | ||
| // If nulls first, the first non-null index | ||
| // Otherwise, the first null index | ||
| null_threshold: usize, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason it is called null_threshold rather than null_index given it is a null index 🤔
| let s_v = self.value(); | ||
| let o_v = other.value(); | ||
|
|
||
| match self.options.descending { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it would be worth specializing on consts NULLS_FIRST and ASC/DESC as well to avoid what looks like runtime overhead in the hot path.
Maybe it doesn't make any practical difference
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's definitely something we could experiment, my expectation is that it won't make a huge difference given how branch heavy merging inherently is
| batch_size: usize, | ||
| ) -> Result<SendableRecordBatchStream> { | ||
| let streams = RowCursorStream::try_new(schema.as_ref(), expressions, streams)?; | ||
| if expressions.len() == 1 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is worth a comment here explaining the rationale for this for future readers. Something like
| if expressions.len() == 1 { | |
| // special case single column primitives to avoid overhead of runtime comparators | |
| if expressions.len() == 1 { |
| } | ||
| } | ||
|
|
||
| pub struct PrimitiveCursorStream<T: ArrowPrimitiveType> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| pub struct PrimitiveCursorStream<T: ArrowPrimitiveType> { | |
| /// Specialized stream for sorts on single primitive columns | |
| pub struct PrimitiveCursorStream<T: ArrowPrimitiveType> { |
|
Thanks @tustvold |
…ive column faster (apache#5897) * Specialize PrimitiveCursor (apache#5882) * Toml format * Review feedback
Which issue does this PR close?
Part of #5882
Rationale for this change
What changes are included in this PR?
Are these changes tested?
Are there any user-facing changes?