Repository navigation
Do not trust Parquet float maximums that leave out NaN - #171
Merged
Merged
Conversation
Parquet writers compute float min/max without NaN, while NaN sorts above every number. A row group, page or file holding 1.0 and NaN has max 1.0, so trusting that maximum pruned it for c > 2, answered MAX(c) with 1.0 from file statistics, and read the column as the constant 1.0. Treat a float column's Parquet maximum as unknown in row-group pruning, page pruning and the file statistics built from the footer. The minimum stays a lower bound. Float columns lose max-side pruning because Parquet statistics carry no NaN count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Parquet writers record a zero minimum as -0.0 whatever the sign of the
stored zeros, so MIN over {0.0, 1.0} came back as -0.0 from footer
statistics. Keep such minimums as bounds only. The opener tests now
prune a float column by its minimum, since its maximum is no longer a
bound.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Parquet statistics leave NaN out of floating-point columns: arrow-rs skips NaN when it computes min/max, as the Parquet spec asks writers to. DataFusion orders floats with arrow's total order, where a NaN with its sign bit clear (the
'NaN'literal) sorts above every other value, soNaN > 2is true. Snowflake agrees: over{1.0, NaN, 1.0},COUNT_IF(k > 2)is 1 andMAX(k)isNaN.A row group, page or file holding
1.0andNaNtherefore has max1.0. When that max is trusted, three things go wrong:WHERE c > 2prunes it and loses the NaN row;MAX(c)is answered from file statistics as1.0;1.0, which turns the NaN rows into1.0.The new sqllogictest reproduces all three on the base branch.
Change
A float column's Parquet maximum is now treated as unknown in three places:
RowGroupPruningStatistics::max_values);PagesPruningStatistics::max_values);statistics_from_parquet_metadata, wheremax_valuebecomesAbsent).The minimum is still a valid lower bound for such a NaN, so
c < xstill prunes. A zero minimum is now marked inexact: writers record it as-0.0whatever the sign of the stored zeros, soMINover{0.0, 1.0}came back as-0.0from footer statistics. Non-float columns are unchanged.A NaN with the sign bit set (e.g.
-'NaN', orinf - infon x86) sorts below every number in arrow's total order. That is a separate, pre-existing difference from Snowflake (which treats every NaN alike), and this change does not alter it.Cost
parquet_statistics.slt, a float equality filter now estimates 5 rows instead of 1.Tests
row_group_float_maximum_does_not_prune(new):c1 > 15keeps both row groups, andc1 < 5still prunes by the minimum.float_maximum_is_absent_from_file_statistics(new): a real file holding[1.0, NaN]gives maxAbsentand min1.0, while the int column keeps its max.parquet_float_nan_statistics.slt(new):count(*) WHERE c > 2= 1,max= NaN,ORDER BY= 1, 1, NaN, andc < 1= 0. The first three fail on the base branch.parquet_float_nan_statistics.sltalso coversORDER BY c DESC LIMIT 1= NaN (the TopK path) andminover{0.0, 1.0}=0.0. The zero case fails without the minimum change.prune_f64_scalar_fun_and_gt, row-group and page variants (f >= 0.1);parquet_statistics.sltplans;datafusion,datafusion-datasource-parquet,datafusion-pruninganddatafusion-physical-optimizer, includingparquet_integration(223) andcore_integration(1,092);🤖 Generated with Claude Code