-
Notifications
You must be signed in to change notification settings - Fork 3.9k
[improvement](be) Optimize projected fixed-width Parquet predicate filtering #65934
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -175,10 +175,10 @@ void ParquetProfile::init(RuntimeProfile* profile) { | |
| TUnit::BYTES, parquet_profile, 1); | ||
| predicate_compaction_count = ADD_CHILD_COUNTER_WITH_LEVEL(profile, "PredicateCompactionCount", | ||
| TUnit::UNIT, parquet_profile, 1); | ||
| plain_predicate_direct_batches = ADD_CHILD_COUNTER_WITH_LEVEL( | ||
| profile, "PlainPredicateDirectBatches", TUnit::UNIT, parquet_profile, 1); | ||
| plain_predicate_direct_rows = ADD_CHILD_COUNTER_WITH_LEVEL(profile, "PlainPredicateDirectRows", | ||
| TUnit::UNIT, parquet_profile, 1); | ||
| fixed_width_predicate_direct_batches = ADD_CHILD_COUNTER_WITH_LEVEL( | ||
| profile, "FixedWidthPredicateDirectBatches", TUnit::UNIT, parquet_profile, 1); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P2] Preserve the profile keys or update their compatibility contract This removes the only |
||
| fixed_width_predicate_direct_rows = ADD_CHILD_COUNTER_WITH_LEVEL( | ||
| profile, "FixedWidthPredicateDirectRows", TUnit::UNIT, parquet_profile, 1); | ||
| dict_filter_rewrite_time = | ||
| ADD_CHILD_TIMER_WITH_LEVEL(profile, "DictFilterRewriteTime", parquet_profile, 1); | ||
| dict_filter_expr_rewrite_time = | ||
|
|
@@ -316,8 +316,8 @@ ParquetScanProfile ParquetProfile::scan_profile() const { | |
| .predicate_compaction_time = predicate_compaction_time, | ||
| .predicate_compaction_bytes = predicate_compaction_bytes, | ||
| .predicate_compaction_count = predicate_compaction_count, | ||
| .plain_predicate_direct_batches = plain_predicate_direct_batches, | ||
| .plain_predicate_direct_rows = plain_predicate_direct_rows, | ||
| .fixed_width_predicate_direct_batches = fixed_width_predicate_direct_batches, | ||
| .fixed_width_predicate_direct_rows = fixed_width_predicate_direct_rows, | ||
| .dict_filter_rewrite_time = dict_filter_rewrite_time, | ||
| .dict_filter_expr_rewrite_time = dict_filter_expr_rewrite_time, | ||
| .dict_filter_read_dict_time = dict_filter_read_dict_time, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -653,14 +653,15 @@ Status decode_selected_nullable_values(IColumn& column, const DataTypeSerDe& ser | |
| return Status::OK(); | ||
| } | ||
|
|
||
| class PlainPredicateConsumer final : public ParquetFixedValueConsumer { | ||
| class FixedWidthPredicateConsumer final : public ParquetFixedValueConsumer { | ||
| public: | ||
| PlainPredicateConsumer(const VExprSPtrs& conjuncts, DataTypePtr data_type, int column_id, | ||
| IColumn::Filter* matches) | ||
| FixedWidthPredicateConsumer(const VExprSPtrs& conjuncts, DataTypePtr data_type, int column_id, | ||
| IColumn::Filter* matches, IColumn* projected_column) | ||
| : _conjuncts(conjuncts), | ||
| _data_type(std::move(data_type)), | ||
| _column_id(column_id), | ||
| _matches(matches) { | ||
| _matches(matches), | ||
| _projected_column(projected_column) { | ||
| DORIS_CHECK(_matches != nullptr); | ||
| } | ||
|
|
||
|
|
@@ -672,6 +673,23 @@ class PlainPredicateConsumer final : public ParquetFixedValueConsumer { | |
| _data_type, _column_id, | ||
| _matches->data() + old_size)); | ||
| } | ||
| if (_projected_column != nullptr) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P2] Avoid per-match-run column appends With alternating predicate results, this loop invokes virtual |
||
| size_t row = 0; | ||
| while (row < num_values) { | ||
| while (row < num_values && (*_matches)[old_size + row] == 0) { | ||
| ++row; | ||
| } | ||
| const size_t run_begin = row; | ||
| while (row < num_values && (*_matches)[old_size + row] != 0) { | ||
| ++row; | ||
| } | ||
| if (row != run_begin) { | ||
| _projected_column->insert_many_raw_data( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P2] Keep native timing complete on projected direct scans Projected predicate columns now append survivors in this branch and no longer pass through |
||
| reinterpret_cast<const char*>(values + run_begin * value_width), | ||
| row - run_begin); | ||
| } | ||
| } | ||
| } | ||
| return Status::OK(); | ||
| } | ||
|
|
||
|
|
@@ -680,6 +698,7 @@ class PlainPredicateConsumer final : public ParquetFixedValueConsumer { | |
| DataTypePtr _data_type; | ||
| int _column_id; | ||
| IColumn::Filter* _matches; | ||
| IColumn* _projected_column; | ||
| }; | ||
|
|
||
| } // namespace | ||
|
|
@@ -1428,11 +1447,10 @@ Status ColumnChunkReader<IN_COLLECTION, OFFSET_INDEX>::materialize_values( | |
| } | ||
|
|
||
| template <bool IN_COLLECTION, bool OFFSET_INDEX> | ||
| bool ColumnChunkReader<IN_COLLECTION, OFFSET_INDEX>::can_filter_plain_values( | ||
| bool ColumnChunkReader<IN_COLLECTION, OFFSET_INDEX>::can_filter_fixed_width_values( | ||
| const VExprSPtrs& conjuncts, int column_id) const { | ||
| if (conjuncts.empty() || _current_encoding != tparquet::Encoding::PLAIN || | ||
| (_metadata.type != tparquet::Type::INT32 && _metadata.type != tparquet::Type::INT64 && | ||
| _metadata.type != tparquet::Type::FLOAT && _metadata.type != tparquet::Type::DOUBLE)) { | ||
| if (conjuncts.empty() || | ||
| !supports_raw_fixed_filter_encoding(_current_encoding, _metadata.type)) { | ||
| return false; | ||
| } | ||
| const auto primitive_type = remove_nullable(_field_schema->data_type)->get_primitive_type(); | ||
|
|
@@ -1453,17 +1471,17 @@ bool ColumnChunkReader<IN_COLLECTION, OFFSET_INDEX>::can_filter_plain_values( | |
| } | ||
|
|
||
| template <bool IN_COLLECTION, bool OFFSET_INDEX> | ||
| Status ColumnChunkReader<IN_COLLECTION, OFFSET_INDEX>::filter_plain_values( | ||
| Status ColumnChunkReader<IN_COLLECTION, OFFSET_INDEX>::filter_fixed_width_values( | ||
| const VExprSPtrs& conjuncts, int column_id, ColumnSelectVector& select_vector, | ||
| NullMap* selected_nulls, IColumn::Filter* physical_matches, IColumn::Filter* row_filter, | ||
| bool* used_filter) { | ||
| NullMap* selected_nulls, IColumn::Filter* physical_matches, IColumn* projected_column, | ||
| IColumn::Filter* row_filter, bool* used_filter) { | ||
| DORIS_CHECK(selected_nulls != nullptr); | ||
| DORIS_CHECK(physical_matches != nullptr); | ||
| DORIS_CHECK(row_filter != nullptr); | ||
| DORIS_CHECK(used_filter != nullptr); | ||
| *used_filter = false; | ||
| row_filter->clear(); | ||
| if (!can_filter_plain_values(conjuncts, column_id)) { | ||
| if (!can_filter_fixed_width_values(conjuncts, column_id)) { | ||
| return Status::OK(); | ||
| } | ||
| if (UNLIKELY(_remaining_num_values < select_vector.num_values())) { | ||
|
|
@@ -1520,8 +1538,8 @@ Status ColumnChunkReader<IN_COLLECTION, OFFSET_INDEX>::filter_plain_values( | |
| if (selection.selected_values == 0) { | ||
| RETURN_IF_ERROR(_page_decoder->skip_values(selection.total_values)); | ||
| } else { | ||
| PlainPredicateConsumer consumer(conjuncts, _field_schema->data_type, column_id, | ||
| physical_matches); | ||
| FixedWidthPredicateConsumer consumer(conjuncts, _field_schema->data_type, column_id, | ||
| physical_matches, projected_column); | ||
| RETURN_IF_ERROR(_page_decoder->decode_selected_fixed_values(selection, consumer)); | ||
| DORIS_CHECK_EQ(physical_matches->size(), selection.selected_values); | ||
| } | ||
|
|
||
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.
[P2] Update and assert the reader registration total
This loop contributes 14 unique registrations, not 16, because each encoding's 10%-selectivity projected case already comes from the preceding loop. The total therefore grows from 137 to 151, while
be/benchmark/parquet/AGENTS.mdstill tells smoke reviewers to expect 137 and to reject a result with a different count. Please assertreader_scenarios().size() == 151and update the current listing/matrix counts (leaving the historical validation record tied to its old commit unchanged).