This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new a724443eb9 [Improvement](predicate) optimize short-circuit predicates
(#18278)
a724443eb9 is described below
commit a724443eb92a84a2c0167033cf08ec95b1369d96
Author: Gabriel <[email protected]>
AuthorDate: Tue Apr 4 10:21:41 2023 +0800
[Improvement](predicate) optimize short-circuit predicates (#18278)
For scan node with no vectorized predicate, the input column for the first
short-circuit predicate is dense and we don't need to access the selector
column.
This PR improve performance by ~30% on TPCH Q3.
---
be/src/exprs/block_bloom_filter.hpp | 2 +-
be/src/exprs/bloom_filter_func.h | 59 ++++++++++++++++++++++++++++--------
be/src/olap/bloom_filter_predicate.h | 36 ++++++++++------------
be/src/olap/column_predicate.h | 15 +++++++++
be/src/olap/comparison_predicate.h | 49 ++++++++++++++----------------
be/src/olap/in_list_predicate.h | 42 +++++++++----------------
be/src/olap/null_predicate.cpp | 13 ++++----
7 files changed, 123 insertions(+), 93 deletions(-)
diff --git a/be/src/exprs/block_bloom_filter.hpp
b/be/src/exprs/block_bloom_filter.hpp
index 2dd6e3cb4f..2a9be09981 100644
--- a/be/src/exprs/block_bloom_filter.hpp
+++ b/be/src/exprs/block_bloom_filter.hpp
@@ -195,7 +195,7 @@ private:
static constexpr uint32_t kRehash[8] __attribute__((aligned(32))) =
{BLOOM_HASH_CONSTANTS};
// Get 32 more bits of randomness from a 32-bit hash:
- static uint32_t rehash32to32(const uint32_t hash) {
+ static ALWAYS_INLINE uint32_t rehash32to32(const uint32_t hash) {
// Constants generated by uuidgen(1) with the -r flag
static constexpr uint64_t m = 0x7850f11ec6d14889ULL;
static constexpr uint64_t a = 0x6773610597ca4c63ULL;
diff --git a/be/src/exprs/bloom_filter_func.h b/be/src/exprs/bloom_filter_func.h
index 7b9236f39a..d127a4c19b 100644
--- a/be/src/exprs/bloom_filter_func.h
+++ b/be/src/exprs/bloom_filter_func.h
@@ -184,7 +184,8 @@ public:
virtual void insert_fixed_len(const char* data) = 0;
virtual uint16_t find_fixed_len_olap_engine(const char* data, const uint8*
nullmap,
- uint16_t* offsets, int number)
= 0;
+ uint16_t* offsets, int number,
+ bool is_parse_column) = 0;
virtual void find_fixed_len(const char* data, const uint8* nullmap, int
number,
uint8* results) = 0;
@@ -213,17 +214,49 @@ struct CommonFindOp {
}
uint16_t find_batch_olap_engine(const BloomFilterAdaptor& bloom_filter,
const char* data,
- const uint8* nullmap, uint16_t* offsets,
int number) const {
+ const uint8* nullmap, uint16_t* offsets,
int number,
+ const bool is_parse_column) const {
uint16_t new_size = 0;
- for (int i = 0; i < number; i++) {
- uint16_t idx = offsets[i];
- if (nullmap != nullptr && nullmap[idx]) {
- continue;
+ if (is_parse_column) {
+ if (nullmap == nullptr) {
+ for (int i = 0; i < number; i++) {
+ uint16_t idx = offsets[i];
+ if (!bloom_filter.test_element(*((T*)data + idx))) {
+ continue;
+ }
+ offsets[new_size++] = idx;
+ }
+ } else {
+ for (int i = 0; i < number; i++) {
+ uint16_t idx = offsets[i];
+ if (nullmap[idx]) {
+ continue;
+ }
+ if (!bloom_filter.test_element(*((T*)data + idx))) {
+ continue;
+ }
+ offsets[new_size++] = idx;
+ }
}
- if (!bloom_filter.test_element(*((T*)data + idx))) {
- continue;
+ } else {
+ if (nullmap == nullptr) {
+ for (int i = 0; i < number; i++) {
+ if (!bloom_filter.test_element(*((T*)data + i))) {
+ continue;
+ }
+ offsets[new_size++] = i;
+ }
+ } else {
+ for (int i = 0; i < number; i++) {
+ if (nullmap[i]) {
+ continue;
+ }
+ if (!bloom_filter.test_element(*((T*)data + i))) {
+ continue;
+ }
+ offsets[new_size++] = i;
+ }
}
- offsets[new_size++] = idx;
}
return new_size;
}
@@ -267,7 +300,8 @@ struct StringFindOp {
}
uint16_t find_batch_olap_engine(const BloomFilterAdaptor& bloom_filter,
const char* data,
- const uint8* nullmap, uint16_t* offsets,
int number) const {
+ const uint8* nullmap, uint16_t* offsets,
int number,
+ const bool is_parse_column) const {
LOG(FATAL) << "StringFindOp does not support find_batch_olap_engine";
return 0;
}
@@ -414,8 +448,9 @@ public:
}
uint16_t find_fixed_len_olap_engine(const char* data, const uint8*
nullmap, uint16_t* offsets,
- int number) override {
- return dummy.find_batch_olap_engine(*_bloom_filter, data, nullmap,
offsets, number);
+ int number, const bool
is_parse_column) override {
+ return dummy.find_batch_olap_engine(*_bloom_filter, data, nullmap,
offsets, number,
+ is_parse_column);
}
void find_fixed_len(const char* data, const uint8* nullmap, int number,
diff --git a/be/src/olap/bloom_filter_predicate.h
b/be/src/olap/bloom_filter_predicate.h
index 986fc0211f..d845871393 100644
--- a/be/src/olap/bloom_filter_predicate.h
+++ b/be/src/olap/bloom_filter_predicate.h
@@ -76,13 +76,13 @@ private:
}
}
} else if (IRuntimeFilter::enable_use_batch(_be_exec_version, T)) {
- new_size = _specific_filter->find_fixed_len_olap_engine(
- (char*)reinterpret_cast<
+ const auto& data =
+ reinterpret_cast<
const
vectorized::PredicateColumnType<PredicateEvaluateType<T>>*>(
&column)
- ->get_data()
- .data(),
- null_map, sel, size);
+ ->get_data();
+ new_size =
_specific_filter->find_fixed_len_olap_engine((char*)data.data(), null_map,
+ sel, size,
data.size() != size);
} else {
uint24_t tmp_uint24_value;
auto get_cell_value = [&tmp_uint24_value](auto& data) {
@@ -95,24 +95,20 @@ private:
}
};
- auto pred_col_data =
+ auto& pred_col =
reinterpret_cast<
const
vectorized::PredicateColumnType<PredicateEvaluateType<T>>*>(
&column)
- ->get_data()
- .data();
- for (uint16_t i = 0; i < size; i++) {
- uint16_t idx = sel[i];
- sel[new_size] = idx;
-
- if constexpr (is_nullable) {
- new_size += !null_map[idx] &&
_specific_filter->find_olap_engine(
-
get_cell_value(pred_col_data[idx]));
- } else {
- new_size +=
-
_specific_filter->find_olap_engine(get_cell_value(pred_col_data[idx]));
- }
- }
+ ->get_data();
+
+ auto pred_col_data = pred_col.data();
+#define EVALUATE_WITH_NULL_IMPL(IDX) \
+ !null_map[IDX] &&
_specific_filter->find_olap_engine(get_cell_value(pred_col_data[IDX]))
+#define EVALUATE_WITHOUT_NULL_IMPL(IDX) \
+ _specific_filter->find_olap_engine(get_cell_value(pred_col_data[IDX]))
+ EVALUATE_BY_SELECTOR(EVALUATE_WITH_NULL_IMPL,
EVALUATE_WITHOUT_NULL_IMPL)
+#undef EVALUATE_WITH_NULL_IMPL
+#undef EVALUATE_WITHOUT_NULL_IMPL
}
return new_size;
}
diff --git a/be/src/olap/column_predicate.h b/be/src/olap/column_predicate.h
index 824b65a07d..a7553740e8 100644
--- a/be/src/olap/column_predicate.h
+++ b/be/src/olap/column_predicate.h
@@ -121,6 +121,21 @@ struct PredicateTypeTraits {
}
};
+#define EVALUATE_BY_SELECTOR(EVALUATE_IMPL_WITH_NULL_MAP,
EVALUATE_IMPL_WITHOUT_NULL_MAP) \
+ const bool is_dense_column = pred_col.size() == size;
\
+ for (uint16_t i = 0; i < size; i++) {
\
+ uint16_t idx = is_dense_column ? i : sel[i];
\
+ if constexpr (is_nullable) {
\
+ if (EVALUATE_IMPL_WITH_NULL_MAP(idx)) {
\
+ sel[new_size++] = idx;
\
+ }
\
+ } else {
\
+ if (EVALUATE_IMPL_WITHOUT_NULL_MAP(idx)) {
\
+ sel[new_size++] = idx;
\
+ }
\
+ }
\
+ }
+
class ColumnPredicate {
public:
explicit ColumnPredicate(uint32_t column_id, bool opposite = false)
diff --git a/be/src/olap/comparison_predicate.h
b/be/src/olap/comparison_predicate.h
index 5bc9115399..e2b85f38b5 100644
--- a/be/src/olap/comparison_predicate.h
+++ b/be/src/olap/comparison_predicate.h
@@ -504,25 +504,6 @@ private:
}
}
- template <bool is_nullable, typename TArray, typename TValue>
- uint16_t _base_loop(uint16_t* sel, uint16_t size, const uint8_t*
__restrict null_map,
- const TArray* __restrict data_array, const TValue&
value) const {
- uint16_t new_size = 0;
- for (uint16_t i = 0; i < size; ++i) {
- uint16_t idx = sel[i];
- if constexpr (is_nullable) {
- if (_opposite ^ (!null_map[idx] && _operator(data_array[idx],
value))) {
- sel[new_size++] = idx;
- }
- } else {
- if (_opposite ^ _operator(data_array[idx], value)) {
- sel[new_size++] = idx;
- }
- }
- }
- return new_size;
- }
-
template <bool is_nullable>
uint16_t _base_evaluate(const vectorized::IColumn* column, const uint8_t*
null_map,
uint16_t* sel, uint16_t size) const {
@@ -530,7 +511,8 @@ private:
if constexpr (std::is_same_v<T, StringRef>) {
auto* dict_column_ptr =
vectorized::check_and_get_column<vectorized::ColumnDictI32>(column);
- auto* data_array = dict_column_ptr->get_data().data();
+ auto& pred_col = dict_column_ptr->get_data();
+ auto pred_col_data = pred_col.data();
auto dict_code =
_find_code_from_dictionary_column(*dict_column_ptr);
if constexpr (PT == PredicateType::EQ) {
@@ -538,20 +520,33 @@ private:
return _opposite ? size : 0;
}
}
-
- return _base_loop<is_nullable>(sel, size, null_map,
data_array, dict_code);
+ uint16_t new_size = 0;
+#define EVALUATE_WITH_NULL_IMPL(IDX) \
+ _opposite ^ (!null_map[IDX] && _operator(pred_col_data[IDX], dict_code))
+#define EVALUATE_WITHOUT_NULL_IMPL(IDX) _opposite ^
_operator(pred_col_data[IDX], dict_code)
+ EVALUATE_BY_SELECTOR(EVALUATE_WITH_NULL_IMPL,
EVALUATE_WITHOUT_NULL_IMPL)
+#undef EVALUATE_WITH_NULL_IMPL
+#undef EVALUATE_WITHOUT_NULL_IMPL
+
+ return new_size;
} else {
LOG(FATAL) << "column_dictionary must use StringRef
predicate.";
return 0;
}
} else {
- auto* data_array =
+ auto& pred_col =
vectorized::check_and_get_column<
vectorized::PredicateColumnType<PredicateEvaluateType<Type>>>(column)
- ->get_data()
- .data();
-
- return _base_loop<is_nullable>(sel, size, null_map, data_array,
_value);
+ ->get_data();
+ auto pred_col_data = pred_col.data();
+ uint16_t new_size = 0;
+#define EVALUATE_WITH_NULL_IMPL(IDX) \
+ _opposite ^ (!null_map[IDX] && _operator(pred_col_data[IDX], _value))
+#define EVALUATE_WITHOUT_NULL_IMPL(IDX) _opposite ^
_operator(pred_col_data[IDX], _value)
+ EVALUATE_BY_SELECTOR(EVALUATE_WITH_NULL_IMPL,
EVALUATE_WITHOUT_NULL_IMPL)
+#undef EVALUATE_WITH_NULL_IMPL
+#undef EVALUATE_WITHOUT_NULL_IMPL
+ return new_size;
}
}
diff --git a/be/src/olap/in_list_predicate.h b/be/src/olap/in_list_predicate.h
index 81ba744935..ac8bd3859c 100644
--- a/be/src/olap/in_list_predicate.h
+++ b/be/src/olap/in_list_predicate.h
@@ -447,33 +447,21 @@ private:
LOG(FATAL) << "column_dictionary must use StringRef
predicate.";
}
} else {
- auto* nested_col_ptr = vectorized::check_and_get_column<
-
vectorized::PredicateColumnType<PredicateEvaluateType<Type>>>(column);
- auto& data_array = nested_col_ptr->get_data();
-
- for (uint16_t i = 0; i < size; i++) {
- uint16_t idx = sel[i];
- if constexpr (is_nullable) {
- if ((*null_map)[idx]) {
- if constexpr (is_opposite) {
- sel[new_size++] = idx;
- }
- continue;
- }
- }
-
- if constexpr (!is_opposite) {
- if (_operator(_values->find(reinterpret_cast<const
T*>(&data_array[idx])),
- false)) {
- sel[new_size++] = idx;
- }
- } else {
- if (!_operator(_values->find(reinterpret_cast<const
T*>(&data_array[idx])),
- false)) {
- sel[new_size++] = idx;
- }
- }
- }
+ auto& pred_col =
+ vectorized::check_and_get_column<
+
vectorized::PredicateColumnType<PredicateEvaluateType<Type>>>(column)
+ ->get_data();
+ auto pred_col_data = pred_col.data();
+
+#define EVALUATE_WITH_NULL_IMPL(IDX) \
+ is_opposite ^ \
+ (!(*null_map)[IDX] && \
+ _operator(_values->find(reinterpret_cast<const
T*>(&pred_col_data[IDX])), false))
+#define EVALUATE_WITHOUT_NULL_IMPL(IDX) \
+ is_opposite ^ _operator(_values->find(reinterpret_cast<const
T*>(&pred_col_data[IDX])), false)
+ EVALUATE_BY_SELECTOR(EVALUATE_WITH_NULL_IMPL,
EVALUATE_WITHOUT_NULL_IMPL)
+#undef EVALUATE_WITH_NULL_IMPL
+#undef EVALUATE_WITHOUT_NULL_IMPL
}
return new_size;
}
diff --git a/be/src/olap/null_predicate.cpp b/be/src/olap/null_predicate.cpp
index c0cc938be8..fe081d9be4 100644
--- a/be/src/olap/null_predicate.cpp
+++ b/be/src/olap/null_predicate.cpp
@@ -53,12 +53,13 @@ uint16_t NullPredicate::evaluate(const vectorized::IColumn&
column, uint16_t* se
if (!nullable->has_null()) {
return _is_null ? 0 : size;
}
- auto& null_map = nullable->get_null_map_data();
- for (uint16_t i = 0; i < size; ++i) {
- uint16_t idx = sel[i];
- sel[new_size] = idx;
- new_size += (null_map[idx] == _is_null);
- }
+ auto& pred_col = nullable->get_null_map_data();
+ constexpr bool is_nullable = true;
+#define EVALUATE_WITH_NULL_IMPL(IDX) pred_col[IDX] == _is_null
+#define EVALUATE_WITHOUT_NULL_IMPL(IDX) true
+ EVALUATE_BY_SELECTOR(EVALUATE_WITH_NULL_IMPL,
EVALUATE_WITHOUT_NULL_IMPL)
+#undef EVALUATE_WITH_NULL_IMPL
+#undef EVALUATE_WITHOUT_NULL_IMPL
return new_size;
} else {
if (_is_null) return 0;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]