You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by GitBox <gi...@apache.org> on 2022/01/05 06:21:43 UTC
[GitHub] [incubator-doris] wangbo opened a new pull request #7613: [Vectorization] support SegmentIterator vectorization
wangbo opened a new pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613
## Proposed changes
Support SegmentIterator vectorization
## Types of changes
What types of changes does your code introduce to Doris?
_Put an `x` in the boxes that apply_
- [ ] Bugfix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation Update (if none of the other choices apply)
- [ ] Code refactor (Modify the code structure, format the code, etc...)
- [ ] Optimization. Including functional usability improvements and performance improvements.
- [ ] Dependency. Such as changes related to third-party components.
- [ ] Other.
## Checklist
_Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._
- [ ] I have created an issue on (Fix #ISSUE) and described the bug/feature there in detail
- [x] Compiling and unit tests pass locally with my changes
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] If these changes need document changes, I have updated the document
- [ ] Any dependent changes have been merged
## Further comments
If this is a relatively large or complex change, kick off the discussion at dev@doris.apache.org by explaining why you chose the solution you did and what alternatives you considered, etc...
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] wangbo commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
wangbo commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781762132
##########
File path: be/src/olap/rowset/segment_v2/binary_dict_page.cpp
##########
@@ -257,23 +257,33 @@ Status BinaryDictPageDecoder::next_batch(size_t* n, vectorized::MutableColumnPtr
const int32_t* data_array = reinterpret_cast<const int32_t*>(_bit_shuffle_ptr->_chunk.data);
size_t start_index = _bit_shuffle_ptr->_cur_index;
- // todo(wb) support nullable
- if (dst->is_predicate_column()) {
+ auto* dst_col_ptr = dst.get();
+ if (dst->is_nullable()) {
+ auto nullable_column = assert_cast<vectorized::ColumnNullable*>(dst.get());
+ dst_col_ptr = nullable_column->get_nested_column_ptr().get();
+
+ // fill null bitmap here, not null;
+ for (int i = 0; i < max_fetch; i++) {
+ nullable_column->get_null_map_data().push_back(0);
+ }
+ }
+
+ if (dst_col_ptr->is_predicate_column()) {
Review comment:
Because current class is ```binary_dict_page```, only ```ColumnStringValue``` will enter this method when the column is a predicate column
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] zuochunwei commented on pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
zuochunwei commented on pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#issuecomment-1007098939
i will review this PR later
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] wangbo commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
wangbo commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r782773055
##########
File path: be/src/olap/rowset/segment_v2/binary_plain_page.h
##########
@@ -235,20 +237,46 @@ class BinaryPlainPageDecoder : public PageDecoder {
}
const size_t max_fetch = std::min(*n, static_cast<size_t>(_num_elems - _cur_idx));
- if (dst->is_predicate_column()) {
+ auto* dst_col_ptr = dst.get();
+ if (dst->is_nullable()) {
+ auto nullable_column = assert_cast<vectorized::ColumnNullable*>(dst.get());
+ dst_col_ptr = nullable_column->get_nested_column_ptr().get();
+ // fill null bitmap here, not null;
+ for (int i = 0; i < max_fetch; i++) {
+ nullable_column->get_null_map_data().push_back(0);
+ }
+ }
+
+ if (dst_col_ptr->is_bitmap()) {
+ auto& bitmap_column = reinterpret_cast<vectorized::ColumnBitmap&>(*dst_col_ptr);
+ for (size_t i = 0; i < max_fetch; i++, _cur_idx++) {
+ const uint32_t start_offset = offset(_cur_idx);
+ uint32_t len = offset(_cur_idx + 1) - start_offset;
+
+ bitmap_column.insert_default();
+ BitmapValue* pvalue = &bitmap_column.get_element(bitmap_column.size() - 1);
+ if (len != 0) {
+ BitmapValue value;
+ value.deserialize(&_data[start_offset]);
+ *pvalue = std::move(value);
Review comment:
I'm not sure, I refer the logic in ```RowBlockV2::_copy_data_to_column```.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] wangbo commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
wangbo commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781761592
##########
File path: be/src/olap/rowset/segment_v2/binary_dict_page.cpp
##########
@@ -257,23 +257,33 @@ Status BinaryDictPageDecoder::next_batch(size_t* n, vectorized::MutableColumnPtr
const int32_t* data_array = reinterpret_cast<const int32_t*>(_bit_shuffle_ptr->_chunk.data);
size_t start_index = _bit_shuffle_ptr->_cur_index;
- // todo(wb) support nullable
- if (dst->is_predicate_column()) {
+ auto* dst_col_ptr = dst.get();
+ if (dst->is_nullable()) {
+ auto nullable_column = assert_cast<vectorized::ColumnNullable*>(dst.get());
+ dst_col_ptr = nullable_column->get_nested_column_ptr().get();
+
+ // fill null bitmap here, not null;
+ for (int i = 0; i < max_fetch; i++) {
Review comment:
👌🏻
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] HappenLee commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
HappenLee commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781723315
##########
File path: be/src/olap/rowset/segment_v2/binary_dict_page.cpp
##########
@@ -257,23 +257,33 @@ Status BinaryDictPageDecoder::next_batch(size_t* n, vectorized::MutableColumnPtr
const int32_t* data_array = reinterpret_cast<const int32_t*>(_bit_shuffle_ptr->_chunk.data);
size_t start_index = _bit_shuffle_ptr->_cur_index;
- // todo(wb) support nullable
- if (dst->is_predicate_column()) {
+ auto* dst_col_ptr = dst.get();
+ if (dst->is_nullable()) {
+ auto nullable_column = assert_cast<vectorized::ColumnNullable*>(dst.get());
+ dst_col_ptr = nullable_column->get_nested_column_ptr().get();
+
+ // fill null bitmap here, not null;
+ for (int i = 0; i < max_fetch; i++) {
Review comment:
consider use memset to SIMD the code, Mark TODO:
##########
File path: be/src/olap/rowset/segment_v2/binary_dict_page.cpp
##########
@@ -257,23 +257,33 @@ Status BinaryDictPageDecoder::next_batch(size_t* n, vectorized::MutableColumnPtr
const int32_t* data_array = reinterpret_cast<const int32_t*>(_bit_shuffle_ptr->_chunk.data);
size_t start_index = _bit_shuffle_ptr->_cur_index;
- // todo(wb) support nullable
- if (dst->is_predicate_column()) {
+ auto* dst_col_ptr = dst.get();
+ if (dst->is_nullable()) {
+ auto nullable_column = assert_cast<vectorized::ColumnNullable*>(dst.get());
+ dst_col_ptr = nullable_column->get_nested_column_ptr().get();
+
+ // fill null bitmap here, not null;
+ for (int i = 0; i < max_fetch; i++) {
+ nullable_column->get_null_map_data().push_back(0);
+ }
+ }
+
+ if (dst_col_ptr->is_predicate_column()) {
Review comment:
dst_col_ptr->is_predicate_column() is `true` means the column is `PredicateColumnType` why `dst_col_prt` convert to vectorized::ColumnStringValue*
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] wangbo commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
wangbo commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781876763
##########
File path: be/src/olap/column_predicate.h
##########
@@ -69,6 +69,8 @@ class ColumnPredicate {
virtual void evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags) const {};
uint32_t column_id() const { return _column_id; }
+ virtual bool is_in_predicate() { return false; }
Review comment:
👌🏻
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] wangbo commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
wangbo commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781880623
##########
File path: be/src/olap/schema.cpp
##########
@@ -147,4 +155,57 @@ vectorized::DataTypePtr Schema::get_data_type_ptr(FieldType type) {
return nullptr;
}
+vectorized::IColumn::MutablePtr Schema::get_predicate_column_nullable_ptr(FieldType type, bool is_null) {
+ vectorized::IColumn::MutablePtr ptr = Schema::get_predicate_column_ptr(type);
+ if (is_null) {
+ return doris::vectorized::ColumnNullable::create(std::move(ptr), doris::vectorized::ColumnUInt8::create());
+ }
+ return ptr;
+}
+
+vectorized::IColumn::MutablePtr Schema::get_predicate_column_ptr(FieldType type) {
+ switch (type) {
+ case OLAP_FIELD_TYPE_TINYINT:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Int8>::create();
Review comment:
This method could just be called once, branch doesn't matter.
And in the actual performance test, this won't cost too much time.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] wangbo commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
wangbo commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781878190
##########
File path: be/src/vec/columns/column.h
##########
@@ -411,10 +413,15 @@ class IColumn : public COW<IColumn> {
// only used in ColumnNullable replace_column_data
virtual void replace_column_data_default(size_t self_row = 0) = 0;
- bool is_date_type() { return is_date; }
+ virtual bool is_date_type() { return is_date; }
Review comment:
This is a temporary implementation, this method would be removed later.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] zuochunwei commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
zuochunwei commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781991236
##########
File path: be/src/olap/rowset/segment_v2/segment_iterator.cpp
##########
@@ -581,9 +586,358 @@ Status SegmentIterator::next_batch(RowBlockV2* block) {
return Status::OK();
}
+/* ---------------------- for vecterization implementation ---------------------- */
+
+// todo(wb) need a UT here
+void SegmentIterator::_vec_init_lazy_materialization() {
+ _is_pred_column.resize(_schema.columns().size(), false);
+
+ std::set<ColumnId> pred_column_ids; // including short_cir_pred_col_id_set and vec_pred_col_id_set
+ _is_all_column_basic_type = true;
+ bool is_predicate_column_exists = false;
+ bool is_non_predicate_column_exists = false;
+
+ if (!_col_predicates.empty()) {
+ is_predicate_column_exists = true;
+
+ std::set<ColumnId> short_cir_pred_col_id_set; // using set for distinct cid
+ std::set<ColumnId> vec_pred_col_id_set;
+
+ for (auto predicate : _col_predicates) {
+ auto cid = predicate->column_id();
+ FieldType type = _schema.column(cid)->type();
+ _is_pred_column[cid] = true;
+ pred_column_ids.insert(cid);
+
+ // for date type which can not be executed in a vectorized way, using short circuit execution
+ if (type == OLAP_FIELD_TYPE_VARCHAR || type == OLAP_FIELD_TYPE_CHAR || type == OLAP_FIELD_TYPE_DECIMAL
+ || type == OLAP_FIELD_TYPE_DATE || predicate->is_in_predicate()) {
+ short_cir_pred_col_id_set.insert(cid);
+ _short_cir_eval_predicate.push_back(predicate);
+ _is_all_column_basic_type = false;
+ } else {
+ vec_pred_col_id_set.insert(predicate->column_id());
+ if (_pre_eval_block_predicate == nullptr) {
+ _pre_eval_block_predicate = new AndBlockColumnPredicate();
+ }
+ reinterpret_cast<MutilColumnBlockPredicate*>(_pre_eval_block_predicate)->add_column_predicate(new SingleColumnBlockPredicate(predicate));
+ }
+ }
+
+ std::set<ColumnId> del_cond_id_set;
+ _opts.delete_condition_predicates.get()->get_all_column_ids(del_cond_id_set);
+ short_cir_pred_col_id_set.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+ pred_column_ids.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+
+ if (_schema.column_ids().size() > pred_column_ids.size()) {
+ for (auto cid : _schema.column_ids()) {
+ if (!_is_pred_column[cid]) {
+ _non_predicate_columns.push_back(cid);
+ is_non_predicate_column_exists = true;
+ }
+ }
+ }
+
+ _vec_pred_column_ids.assign(vec_pred_col_id_set.cbegin(), vec_pred_col_id_set.cend());
+ _short_cir_pred_column_ids.assign(short_cir_pred_col_id_set.cbegin(), short_cir_pred_col_id_set.cend());
+ } else {
+ _is_all_column_basic_type = false;
+ is_non_predicate_column_exists = true;
+ for (auto cid : _schema.column_ids()) {
+ _non_predicate_columns.push_back(cid);
+ }
+ }
+
+ // note(wb) in following cases we disable lazy materialization
+ // case 1: when all column is basic type(is_all_column_basic_type = true)
+ // because we think `seek and read` cost > read page cost, lazy materialize may cause more `seek and read`, so disable it
+ // case 2: all column is predicate column
+ // case 3: all column is not predicate column
+ // todo(wb) need further research more lazy materialization rule, such as get more info from `statistics` for better decision
+ if (_is_all_column_basic_type) {
+ std::set<ColumnId> pred_set(_vec_pred_column_ids.begin(), _vec_pred_column_ids.end());
+ std::set<ColumnId> non_pred_set(_non_predicate_columns.begin(), _non_predicate_columns.end());
+
+ // when _is_all_column_basic_type = true, _first_read_column_ids should keep the same order with _schema.column_ids which stands for return column order
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (pred_set.find(cid) != pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ } else if (non_pred_set.find(cid) != non_pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ _is_pred_column[cid] = true; // in this case, non-predicate column should also be filtered by sel idx, so we regard it as pred columns
+ }
+ }
+
+ } else if (is_predicate_column_exists && !is_non_predicate_column_exists) {
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ } else if (!is_predicate_column_exists && is_non_predicate_column_exists) {
+ for (auto cid : _non_predicate_columns) {
+ _first_read_column_ids.push_back(cid);
+ }
+ } else {
+ _lazy_materialization_read = true;
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ }
+
+ // make _schema_block_id_map
+ _schema_block_id_map.resize(_schema.columns().size());
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ _schema_block_id_map[cid] = i;
+ }
+
+}
+
+Status SegmentIterator::_read_columns(const std::vector<ColumnId>& column_ids, vectorized::MutableColumns& column_block, size_t nrows) {
+ for (auto cid : column_ids) {
+ auto& column = column_block[cid];
+ size_t rows_read = nrows;
+ RETURN_IF_ERROR(_column_iterators[cid]->next_batch(&rows_read, column));
+ DCHECK_EQ(nrows, rows_read);
+ }
+ return Status::OK();
+}
+
+void SegmentIterator::_init_current_block(vectorized::Block* block, std::vector<vectorized::MutableColumnPtr>& current_columns) {
+ bool is_block_mem_reuse= block->mem_reuse();
+ if (is_block_mem_reuse) {
+ size_t column_to_keep = _schema.num_column_ids();
+ for (int i = block->columns() - 1; i >= column_to_keep; i--) {
+ block->erase(i);
+ }
+ block->clear_column_data();
+ } else { // pre fill output block here
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ auto* column_desc = _schema.columns()[cid];
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ if (column_desc->is_nullable()) {
+ block->insert({nullptr, std::make_shared<vectorized::DataTypeNullable>(std::move(data_type)), column_desc->name()});
+ } else {
+ block->insert({nullptr, std::move(data_type), column_desc->name()});
+ }
+ }
+ }
+
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (_is_pred_column[cid]) { //todo(wb) maybe we can relase it after output block
+ current_columns[cid]->clear();
+ } else { // non-predicate column
+ auto &column_desc = _schema.columns()[cid];
+ if (is_block_mem_reuse) {
+ current_columns[cid] = std::move(*block->get_by_position(i).column).mutate();
+ } else {
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ if (column_desc->is_nullable()) {
+ current_columns[cid] = doris::vectorized::ColumnNullable::create(
+ std::move(data_type->create_column()), doris::vectorized::ColumnUInt8::create());
+ } else {
+ current_columns[cid] = data_type->create_column();
+ }
+ }
+ if (column_desc->type() == OLAP_FIELD_TYPE_DATE) {
+ current_columns[cid]->set_date_type();
+ } else if (column_desc->type() == OLAP_FIELD_TYPE_DATETIME) {
+ current_columns[cid]->set_datetime_type();
+ }
+ }
+ }
+}
+
+void SegmentIterator::_output_non_pred_columns(vectorized::Block* block, bool is_block_mem_reuse) {
+ for (auto cid : _non_predicate_columns) {
+ block->replace_by_position(_schema_block_id_map[cid], std::move(_current_return_columns[cid]));
+ }
+ }
+
+void SegmentIterator::_output_column_by_sel_idx(vectorized::Block* block, std::vector<ColumnId> columnIds,
+ uint16_t* sel_rowid_idx, uint16_t select_size, bool is_block_mem_reuse) {
+ for (auto cid : columnIds) {
+ auto &column_ptr = _current_return_columns[cid];
+ if (is_block_mem_reuse) {
+ column_ptr->filter_by_selector(sel_rowid_idx, select_size,
+ &block->get_by_position(_schema_block_id_map[cid]).column);
+ } else {
+ block->replace_by_position(_schema_block_id_map[cid],
+ (*column_ptr).get_ptr()->filter_by_selector(sel_rowid_idx, select_size));
+ }
+ }
+ }
+
+
+Status SegmentIterator::_read_columns_by_index(uint32_t nrows_read_limit, uint32_t& nrows_read, bool set_block_rowid) {
+ do {
+ uint32_t range_from;
+ uint32_t range_to;
+ bool has_next_range =
+ _range_iter->next_range(nrows_read_limit - nrows_read, &range_from, &range_to);
+ if (!has_next_range) {
+ break;
+ }
+ if (_cur_rowid == 0 || _cur_rowid != range_from) {
+ _cur_rowid = range_from;
+ RETURN_IF_ERROR(_seek_columns(_first_read_column_ids, _cur_rowid));
+ }
+ size_t rows_to_read = range_to - range_from;
+ RETURN_IF_ERROR(_read_columns(_first_read_column_ids, _current_return_columns, rows_to_read));
+ _cur_rowid += rows_to_read;
+ if (set_block_rowid) {
+ for (uint32_t rid = range_from; rid < range_to; rid++) {
+ _block_rowids[nrows_read++] = rid;
+ }
+ } else {
+ nrows_read += rows_to_read;
+ }
+ } while (nrows_read < nrows_read_limit);
+ return Status::OK();
+}
+
+void SegmentIterator::_evaluate_vectorization_predicate(uint16_t* sel_rowid_idx, uint16_t& selected_size) {
+ uint16_t new_size = 0;
+ if (_vec_pred_column_ids.size() == 0) {
+ for (uint32_t i = 0; i < selected_size; ++i) {
+ sel_rowid_idx[new_size++] = i;
+ }
+ return;
+ }
+
+ uint16_t original_size = selected_size;
+ bool ret_flags[selected_size];
+ memset(ret_flags, 1, selected_size);
+ _pre_eval_block_predicate->evaluate_vec(_current_return_columns, selected_size, ret_flags);
+
+ for (uint32_t i = 0; i < selected_size; ++i) {
+ if (ret_flags[i]) {
+ sel_rowid_idx[new_size++] = i;
+ }
+ }
+
+ _opts.stats->rows_vec_cond_filtered += original_size - new_size;
+ selected_size = new_size;
+}
+
+void SegmentIterator::_evaluate_short_circuit_predicate(uint16_t* vec_sel_rowid_idx, uint16_t* selected_size_ptr) {
+ if (_short_cir_pred_column_ids.size() == 0) {
+ return;
+ }
+
+ for (auto column_predicate : _short_cir_eval_predicate) {
+ auto column_id = column_predicate->column_id();
+ auto& short_cir_column = _current_return_columns[column_id];
+ column_predicate->evaluate(*short_cir_column, vec_sel_rowid_idx, selected_size_ptr);
+ }
+
+ // evaluate delete condition
+ _opts.delete_condition_predicates->evaluate(_current_return_columns, vec_sel_rowid_idx, selected_size_ptr);
+}
+
+void SegmentIterator::_read_columns_by_rowids(std::vector<ColumnId>& read_column_ids, std::vector<rowid_t>& rowid_vector,
+ uint16_t* sel_rowid_idx, size_t select_size, vectorized::MutableColumns* mutable_columns) {
+ size_t start_idx = 0;
+ while (start_idx < select_size) {
+ size_t end_idx = start_idx + 1;
+ while (end_idx < select_size && (rowid_vector[sel_rowid_idx[end_idx - 1]] == rowid_vector[sel_rowid_idx[end_idx]] - 1)) {
+ end_idx++;
+ }
+ size_t range = end_idx - start_idx;
+ _seek_columns(read_column_ids, rowid_vector[sel_rowid_idx[start_idx]]);
+ _read_columns(read_column_ids, *mutable_columns, range);
+ start_idx += range;
+ }
+}
+
Status SegmentIterator::next_batch(vectorized::Block* block) {
- //TODO
- return Status::NotSupported("not implement now");
+ bool is_mem_reuse = block->mem_reuse();
+ SCOPED_RAW_TIMER(&_opts.stats->block_load_ns);
+ if (UNLIKELY(!_inited)) {
+ RETURN_IF_ERROR(_init(true));
+ _inited = true;
+ if (_vec_pred_column_ids.size() > 0 || _short_cir_pred_column_ids.size() > 0) {
+ _block_rowids.reserve(_opts.block_row_max);
+ }
+ _current_return_columns.resize(_schema.columns().size());
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (_is_pred_column[cid]) {
+ auto& column_desc = _schema.columns()[cid];
+ _current_return_columns[cid] = Schema::get_predicate_column_nullable_ptr(column_desc->type(), column_desc->is_nullable());
+ _current_return_columns[cid]->reserve(_opts.block_row_max);
+ }
+ }
+ }
+
+ _init_current_block(block, _current_return_columns);
+
+ uint32_t nrows_read = 0;
+ uint32_t nrows_read_limit = _opts.block_row_max;
+ _read_columns_by_index(nrows_read_limit, nrows_read, _col_predicates.size() > 0);
+
+ _opts.stats->blocks_load += 1;
+ _opts.stats->raw_rows_read += nrows_read;
+
+ if (nrows_read == 0) {
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ // todo(wb) abstract make column where
+ if (!_is_pred_column[cid]) { // non-predicate
+ block->replace_by_position(i, std::move(_current_return_columns[cid]));
+ } else { // predicate
+ if (!is_mem_reuse) {
+ auto* column_desc = _schema.columns()[cid];
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ block->replace_by_position(i, data_type->create_column());
+ }
+ }
+ // not sure whether block is clear before enter segmentIter, so clear it here.
+ if (is_mem_reuse) {
Review comment:
it' s not a good idea to clear here. think who should take responsibility for clear job.
in another words, we should wrap the reuse logic rather than exposed everywhere
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] wangbo commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
wangbo commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781762541
##########
File path: be/src/olap/schema.cpp
##########
@@ -147,4 +155,57 @@ vectorized::DataTypePtr Schema::get_data_type_ptr(FieldType type) {
return nullptr;
}
+vectorized::IColumn::MutablePtr Schema::get_predicate_column_nullable_ptr(FieldType type, bool is_null) {
+ vectorized::IColumn::MutablePtr ptr = Schema::get_predicate_column_ptr(type);
+ if (is_null) {
+ return doris::vectorized::ColumnNullable::create(std::move(ptr), doris::vectorized::ColumnUInt8::create());
+ }
+ return ptr;
+}
+
+vectorized::IColumn::MutablePtr Schema::get_predicate_column_ptr(FieldType type) {
+ switch (type) {
+ case OLAP_FIELD_TYPE_TINYINT:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Int8>::create();
+
+ case OLAP_FIELD_TYPE_SMALLINT:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Int16>::create();
+
+ case OLAP_FIELD_TYPE_INT:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Int32>::create();
+
+ case OLAP_FIELD_TYPE_FLOAT:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Float32>::create();
+
+ case OLAP_FIELD_TYPE_DOUBLE:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Float64>::create();
+
+ case OLAP_FIELD_TYPE_BIGINT:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Int64>::create();
+
+ case OLAP_FIELD_TYPE_LARGEINT:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Int128>::create();
+
+ case OLAP_FIELD_TYPE_DATE: {
+ return doris::vectorized::PredicateColumnType<uint24_t>::create();
+ }
+ case OLAP_FIELD_TYPE_DATETIME: {
+ return doris::vectorized::PredicateColumnType<uint64_t>::create();
+ }
+
+ case OLAP_FIELD_TYPE_CHAR:
+ case OLAP_FIELD_TYPE_VARCHAR:
+ return doris::vectorized::PredicateColumnType<StringValue>::create();
Review comment:
I will add a todo here.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] zuochunwei commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
zuochunwei commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781978307
##########
File path: be/src/olap/rowset/segment_v2/segment_iterator.cpp
##########
@@ -581,9 +586,358 @@ Status SegmentIterator::next_batch(RowBlockV2* block) {
return Status::OK();
}
+/* ---------------------- for vecterization implementation ---------------------- */
+
+// todo(wb) need a UT here
+void SegmentIterator::_vec_init_lazy_materialization() {
+ _is_pred_column.resize(_schema.columns().size(), false);
+
+ std::set<ColumnId> pred_column_ids; // including short_cir_pred_col_id_set and vec_pred_col_id_set
+ _is_all_column_basic_type = true;
+ bool is_predicate_column_exists = false;
+ bool is_non_predicate_column_exists = false;
+
+ if (!_col_predicates.empty()) {
+ is_predicate_column_exists = true;
+
+ std::set<ColumnId> short_cir_pred_col_id_set; // using set for distinct cid
+ std::set<ColumnId> vec_pred_col_id_set;
+
+ for (auto predicate : _col_predicates) {
+ auto cid = predicate->column_id();
+ FieldType type = _schema.column(cid)->type();
+ _is_pred_column[cid] = true;
+ pred_column_ids.insert(cid);
+
+ // for date type which can not be executed in a vectorized way, using short circuit execution
+ if (type == OLAP_FIELD_TYPE_VARCHAR || type == OLAP_FIELD_TYPE_CHAR || type == OLAP_FIELD_TYPE_DECIMAL
+ || type == OLAP_FIELD_TYPE_DATE || predicate->is_in_predicate()) {
+ short_cir_pred_col_id_set.insert(cid);
+ _short_cir_eval_predicate.push_back(predicate);
+ _is_all_column_basic_type = false;
+ } else {
+ vec_pred_col_id_set.insert(predicate->column_id());
+ if (_pre_eval_block_predicate == nullptr) {
+ _pre_eval_block_predicate = new AndBlockColumnPredicate();
+ }
+ reinterpret_cast<MutilColumnBlockPredicate*>(_pre_eval_block_predicate)->add_column_predicate(new SingleColumnBlockPredicate(predicate));
+ }
+ }
+
+ std::set<ColumnId> del_cond_id_set;
+ _opts.delete_condition_predicates.get()->get_all_column_ids(del_cond_id_set);
+ short_cir_pred_col_id_set.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+ pred_column_ids.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+
+ if (_schema.column_ids().size() > pred_column_ids.size()) {
+ for (auto cid : _schema.column_ids()) {
+ if (!_is_pred_column[cid]) {
+ _non_predicate_columns.push_back(cid);
+ is_non_predicate_column_exists = true;
+ }
+ }
+ }
+
+ _vec_pred_column_ids.assign(vec_pred_col_id_set.cbegin(), vec_pred_col_id_set.cend());
+ _short_cir_pred_column_ids.assign(short_cir_pred_col_id_set.cbegin(), short_cir_pred_col_id_set.cend());
+ } else {
+ _is_all_column_basic_type = false;
+ is_non_predicate_column_exists = true;
+ for (auto cid : _schema.column_ids()) {
+ _non_predicate_columns.push_back(cid);
+ }
+ }
+
+ // note(wb) in following cases we disable lazy materialization
+ // case 1: when all column is basic type(is_all_column_basic_type = true)
+ // because we think `seek and read` cost > read page cost, lazy materialize may cause more `seek and read`, so disable it
+ // case 2: all column is predicate column
+ // case 3: all column is not predicate column
+ // todo(wb) need further research more lazy materialization rule, such as get more info from `statistics` for better decision
+ if (_is_all_column_basic_type) {
+ std::set<ColumnId> pred_set(_vec_pred_column_ids.begin(), _vec_pred_column_ids.end());
+ std::set<ColumnId> non_pred_set(_non_predicate_columns.begin(), _non_predicate_columns.end());
+
+ // when _is_all_column_basic_type = true, _first_read_column_ids should keep the same order with _schema.column_ids which stands for return column order
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (pred_set.find(cid) != pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ } else if (non_pred_set.find(cid) != non_pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ _is_pred_column[cid] = true; // in this case, non-predicate column should also be filtered by sel idx, so we regard it as pred columns
+ }
+ }
+
+ } else if (is_predicate_column_exists && !is_non_predicate_column_exists) {
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ } else if (!is_predicate_column_exists && is_non_predicate_column_exists) {
+ for (auto cid : _non_predicate_columns) {
+ _first_read_column_ids.push_back(cid);
+ }
+ } else {
+ _lazy_materialization_read = true;
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ }
+
+ // make _schema_block_id_map
+ _schema_block_id_map.resize(_schema.columns().size());
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ _schema_block_id_map[cid] = i;
+ }
+
+}
+
+Status SegmentIterator::_read_columns(const std::vector<ColumnId>& column_ids, vectorized::MutableColumns& column_block, size_t nrows) {
+ for (auto cid : column_ids) {
+ auto& column = column_block[cid];
+ size_t rows_read = nrows;
+ RETURN_IF_ERROR(_column_iterators[cid]->next_batch(&rows_read, column));
+ DCHECK_EQ(nrows, rows_read);
+ }
+ return Status::OK();
+}
+
+void SegmentIterator::_init_current_block(vectorized::Block* block, std::vector<vectorized::MutableColumnPtr>& current_columns) {
Review comment:
why pass member data _current_return_columns as member function‘s argument?
why not use _current_return_columns in _init_current_block directly?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] zuochunwei commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
zuochunwei commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781790246
##########
File path: be/src/vec/columns/column_nullable.h
##########
@@ -130,7 +130,13 @@ class ColumnNullable final : public COWHelper<IColumn, ColumnNullable> {
return false;
}
+ bool is_date_type() override { return get_nested_column().is_date_type(); }
Review comment:
same problems to above
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] HappenLee commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
HappenLee commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781748247
##########
File path: be/src/olap/schema.cpp
##########
@@ -147,4 +155,57 @@ vectorized::DataTypePtr Schema::get_data_type_ptr(FieldType type) {
return nullptr;
}
+vectorized::IColumn::MutablePtr Schema::get_predicate_column_nullable_ptr(FieldType type, bool is_null) {
+ vectorized::IColumn::MutablePtr ptr = Schema::get_predicate_column_ptr(type);
+ if (is_null) {
+ return doris::vectorized::ColumnNullable::create(std::move(ptr), doris::vectorized::ColumnUInt8::create());
+ }
+ return ptr;
+}
+
+vectorized::IColumn::MutablePtr Schema::get_predicate_column_ptr(FieldType type) {
+ switch (type) {
+ case OLAP_FIELD_TYPE_TINYINT:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Int8>::create();
+
+ case OLAP_FIELD_TYPE_SMALLINT:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Int16>::create();
+
+ case OLAP_FIELD_TYPE_INT:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Int32>::create();
+
+ case OLAP_FIELD_TYPE_FLOAT:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Float32>::create();
+
+ case OLAP_FIELD_TYPE_DOUBLE:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Float64>::create();
+
+ case OLAP_FIELD_TYPE_BIGINT:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Int64>::create();
+
+ case OLAP_FIELD_TYPE_LARGEINT:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Int128>::create();
+
+ case OLAP_FIELD_TYPE_DATE: {
+ return doris::vectorized::PredicateColumnType<uint24_t>::create();
+ }
+ case OLAP_FIELD_TYPE_DATETIME: {
+ return doris::vectorized::PredicateColumnType<uint64_t>::create();
+ }
+
+ case OLAP_FIELD_TYPE_CHAR:
+ case OLAP_FIELD_TYPE_VARCHAR:
+ return doris::vectorized::PredicateColumnType<StringValue>::create();
Review comment:
maybe should add OLAP_FIELD_TYPE_STRING
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] wangbo commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
wangbo commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r782773886
##########
File path: be/src/olap/rowset/segment_v2/segment_iterator.cpp
##########
@@ -581,9 +586,358 @@ Status SegmentIterator::next_batch(RowBlockV2* block) {
return Status::OK();
}
+/* ---------------------- for vecterization implementation ---------------------- */
+
+// todo(wb) need a UT here
+void SegmentIterator::_vec_init_lazy_materialization() {
+ _is_pred_column.resize(_schema.columns().size(), false);
+
+ std::set<ColumnId> pred_column_ids; // including short_cir_pred_col_id_set and vec_pred_col_id_set
+ _is_all_column_basic_type = true;
+ bool is_predicate_column_exists = false;
+ bool is_non_predicate_column_exists = false;
+
+ if (!_col_predicates.empty()) {
+ is_predicate_column_exists = true;
+
+ std::set<ColumnId> short_cir_pred_col_id_set; // using set for distinct cid
+ std::set<ColumnId> vec_pred_col_id_set;
+
+ for (auto predicate : _col_predicates) {
+ auto cid = predicate->column_id();
+ FieldType type = _schema.column(cid)->type();
+ _is_pred_column[cid] = true;
+ pred_column_ids.insert(cid);
+
+ // for date type which can not be executed in a vectorized way, using short circuit execution
+ if (type == OLAP_FIELD_TYPE_VARCHAR || type == OLAP_FIELD_TYPE_CHAR || type == OLAP_FIELD_TYPE_DECIMAL
+ || type == OLAP_FIELD_TYPE_DATE || predicate->is_in_predicate()) {
+ short_cir_pred_col_id_set.insert(cid);
+ _short_cir_eval_predicate.push_back(predicate);
+ _is_all_column_basic_type = false;
+ } else {
+ vec_pred_col_id_set.insert(predicate->column_id());
+ if (_pre_eval_block_predicate == nullptr) {
+ _pre_eval_block_predicate = new AndBlockColumnPredicate();
+ }
+ reinterpret_cast<MutilColumnBlockPredicate*>(_pre_eval_block_predicate)->add_column_predicate(new SingleColumnBlockPredicate(predicate));
+ }
+ }
+
+ std::set<ColumnId> del_cond_id_set;
+ _opts.delete_condition_predicates.get()->get_all_column_ids(del_cond_id_set);
+ short_cir_pred_col_id_set.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+ pred_column_ids.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+
+ if (_schema.column_ids().size() > pred_column_ids.size()) {
+ for (auto cid : _schema.column_ids()) {
+ if (!_is_pred_column[cid]) {
+ _non_predicate_columns.push_back(cid);
+ is_non_predicate_column_exists = true;
+ }
+ }
+ }
+
+ _vec_pred_column_ids.assign(vec_pred_col_id_set.cbegin(), vec_pred_col_id_set.cend());
+ _short_cir_pred_column_ids.assign(short_cir_pred_col_id_set.cbegin(), short_cir_pred_col_id_set.cend());
+ } else {
+ _is_all_column_basic_type = false;
+ is_non_predicate_column_exists = true;
+ for (auto cid : _schema.column_ids()) {
+ _non_predicate_columns.push_back(cid);
+ }
+ }
+
+ // note(wb) in following cases we disable lazy materialization
+ // case 1: when all column is basic type(is_all_column_basic_type = true)
+ // because we think `seek and read` cost > read page cost, lazy materialize may cause more `seek and read`, so disable it
+ // case 2: all column is predicate column
+ // case 3: all column is not predicate column
+ // todo(wb) need further research more lazy materialization rule, such as get more info from `statistics` for better decision
+ if (_is_all_column_basic_type) {
+ std::set<ColumnId> pred_set(_vec_pred_column_ids.begin(), _vec_pred_column_ids.end());
+ std::set<ColumnId> non_pred_set(_non_predicate_columns.begin(), _non_predicate_columns.end());
+
+ // when _is_all_column_basic_type = true, _first_read_column_ids should keep the same order with _schema.column_ids which stands for return column order
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (pred_set.find(cid) != pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ } else if (non_pred_set.find(cid) != non_pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ _is_pred_column[cid] = true; // in this case, non-predicate column should also be filtered by sel idx, so we regard it as pred columns
+ }
+ }
+
+ } else if (is_predicate_column_exists && !is_non_predicate_column_exists) {
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ } else if (!is_predicate_column_exists && is_non_predicate_column_exists) {
+ for (auto cid : _non_predicate_columns) {
+ _first_read_column_ids.push_back(cid);
+ }
+ } else {
+ _lazy_materialization_read = true;
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ }
+
+ // make _schema_block_id_map
+ _schema_block_id_map.resize(_schema.columns().size());
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ _schema_block_id_map[cid] = i;
+ }
+
+}
+
+Status SegmentIterator::_read_columns(const std::vector<ColumnId>& column_ids, vectorized::MutableColumns& column_block, size_t nrows) {
+ for (auto cid : column_ids) {
+ auto& column = column_block[cid];
+ size_t rows_read = nrows;
+ RETURN_IF_ERROR(_column_iterators[cid]->next_batch(&rows_read, column));
+ DCHECK_EQ(nrows, rows_read);
+ }
+ return Status::OK();
+}
+
+void SegmentIterator::_init_current_block(vectorized::Block* block, std::vector<vectorized::MutableColumnPtr>& current_columns) {
+ bool is_block_mem_reuse= block->mem_reuse();
+ if (is_block_mem_reuse) {
+ size_t column_to_keep = _schema.num_column_ids();
+ for (int i = block->columns() - 1; i >= column_to_keep; i--) {
+ block->erase(i);
+ }
+ block->clear_column_data();
+ } else { // pre fill output block here
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ auto* column_desc = _schema.columns()[cid];
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ if (column_desc->is_nullable()) {
+ block->insert({nullptr, std::make_shared<vectorized::DataTypeNullable>(std::move(data_type)), column_desc->name()});
+ } else {
+ block->insert({nullptr, std::move(data_type), column_desc->name()});
+ }
+ }
+ }
+
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (_is_pred_column[cid]) { //todo(wb) maybe we can relase it after output block
+ current_columns[cid]->clear();
+ } else { // non-predicate column
+ auto &column_desc = _schema.columns()[cid];
+ if (is_block_mem_reuse) {
+ current_columns[cid] = std::move(*block->get_by_position(i).column).mutate();
+ } else {
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ if (column_desc->is_nullable()) {
+ current_columns[cid] = doris::vectorized::ColumnNullable::create(
+ std::move(data_type->create_column()), doris::vectorized::ColumnUInt8::create());
+ } else {
+ current_columns[cid] = data_type->create_column();
+ }
+ }
+ if (column_desc->type() == OLAP_FIELD_TYPE_DATE) {
+ current_columns[cid]->set_date_type();
+ } else if (column_desc->type() == OLAP_FIELD_TYPE_DATETIME) {
+ current_columns[cid]->set_datetime_type();
+ }
+ }
+ }
+}
+
+void SegmentIterator::_output_non_pred_columns(vectorized::Block* block, bool is_block_mem_reuse) {
+ for (auto cid : _non_predicate_columns) {
+ block->replace_by_position(_schema_block_id_map[cid], std::move(_current_return_columns[cid]));
+ }
+ }
+
+void SegmentIterator::_output_column_by_sel_idx(vectorized::Block* block, std::vector<ColumnId> columnIds,
+ uint16_t* sel_rowid_idx, uint16_t select_size, bool is_block_mem_reuse) {
+ for (auto cid : columnIds) {
+ auto &column_ptr = _current_return_columns[cid];
+ if (is_block_mem_reuse) {
+ column_ptr->filter_by_selector(sel_rowid_idx, select_size,
+ &block->get_by_position(_schema_block_id_map[cid]).column);
+ } else {
+ block->replace_by_position(_schema_block_id_map[cid],
+ (*column_ptr).get_ptr()->filter_by_selector(sel_rowid_idx, select_size));
+ }
+ }
+ }
+
+
+Status SegmentIterator::_read_columns_by_index(uint32_t nrows_read_limit, uint32_t& nrows_read, bool set_block_rowid) {
+ do {
+ uint32_t range_from;
+ uint32_t range_to;
+ bool has_next_range =
+ _range_iter->next_range(nrows_read_limit - nrows_read, &range_from, &range_to);
+ if (!has_next_range) {
+ break;
+ }
+ if (_cur_rowid == 0 || _cur_rowid != range_from) {
+ _cur_rowid = range_from;
+ RETURN_IF_ERROR(_seek_columns(_first_read_column_ids, _cur_rowid));
+ }
+ size_t rows_to_read = range_to - range_from;
+ RETURN_IF_ERROR(_read_columns(_first_read_column_ids, _current_return_columns, rows_to_read));
+ _cur_rowid += rows_to_read;
+ if (set_block_rowid) {
+ for (uint32_t rid = range_from; rid < range_to; rid++) {
+ _block_rowids[nrows_read++] = rid;
+ }
+ } else {
+ nrows_read += rows_to_read;
+ }
+ } while (nrows_read < nrows_read_limit);
+ return Status::OK();
+}
+
+void SegmentIterator::_evaluate_vectorization_predicate(uint16_t* sel_rowid_idx, uint16_t& selected_size) {
+ uint16_t new_size = 0;
+ if (_vec_pred_column_ids.size() == 0) {
+ for (uint32_t i = 0; i < selected_size; ++i) {
+ sel_rowid_idx[new_size++] = i;
+ }
+ return;
+ }
+
+ uint16_t original_size = selected_size;
+ bool ret_flags[selected_size];
+ memset(ret_flags, 1, selected_size);
+ _pre_eval_block_predicate->evaluate_vec(_current_return_columns, selected_size, ret_flags);
+
+ for (uint32_t i = 0; i < selected_size; ++i) {
+ if (ret_flags[i]) {
+ sel_rowid_idx[new_size++] = i;
+ }
+ }
+
+ _opts.stats->rows_vec_cond_filtered += original_size - new_size;
+ selected_size = new_size;
+}
+
+void SegmentIterator::_evaluate_short_circuit_predicate(uint16_t* vec_sel_rowid_idx, uint16_t* selected_size_ptr) {
+ if (_short_cir_pred_column_ids.size() == 0) {
+ return;
+ }
+
+ for (auto column_predicate : _short_cir_eval_predicate) {
+ auto column_id = column_predicate->column_id();
+ auto& short_cir_column = _current_return_columns[column_id];
+ column_predicate->evaluate(*short_cir_column, vec_sel_rowid_idx, selected_size_ptr);
+ }
+
+ // evaluate delete condition
+ _opts.delete_condition_predicates->evaluate(_current_return_columns, vec_sel_rowid_idx, selected_size_ptr);
+}
+
+void SegmentIterator::_read_columns_by_rowids(std::vector<ColumnId>& read_column_ids, std::vector<rowid_t>& rowid_vector,
+ uint16_t* sel_rowid_idx, size_t select_size, vectorized::MutableColumns* mutable_columns) {
+ size_t start_idx = 0;
+ while (start_idx < select_size) {
+ size_t end_idx = start_idx + 1;
+ while (end_idx < select_size && (rowid_vector[sel_rowid_idx[end_idx - 1]] == rowid_vector[sel_rowid_idx[end_idx]] - 1)) {
+ end_idx++;
+ }
+ size_t range = end_idx - start_idx;
+ _seek_columns(read_column_ids, rowid_vector[sel_rowid_idx[start_idx]]);
+ _read_columns(read_column_ids, *mutable_columns, range);
+ start_idx += range;
+ }
+}
+
Status SegmentIterator::next_batch(vectorized::Block* block) {
- //TODO
- return Status::NotSupported("not implement now");
+ bool is_mem_reuse = block->mem_reuse();
+ SCOPED_RAW_TIMER(&_opts.stats->block_load_ns);
+ if (UNLIKELY(!_inited)) {
+ RETURN_IF_ERROR(_init(true));
Review comment:
This method could only be called once in a segment_iterator's lifecycle, this is not frequently at all.
Add a args just for code reuse, you can see the method ```_init``` 's implementation.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] zuochunwei commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
zuochunwei commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781934093
##########
File path: be/src/olap/rowset/segment_v2/binary_plain_page.h
##########
@@ -235,20 +237,46 @@ class BinaryPlainPageDecoder : public PageDecoder {
}
const size_t max_fetch = std::min(*n, static_cast<size_t>(_num_elems - _cur_idx));
- if (dst->is_predicate_column()) {
+ auto* dst_col_ptr = dst.get();
+ if (dst->is_nullable()) {
+ auto nullable_column = assert_cast<vectorized::ColumnNullable*>(dst.get());
+ dst_col_ptr = nullable_column->get_nested_column_ptr().get();
+ // fill null bitmap here, not null;
+ for (int i = 0; i < max_fetch; i++) {
+ nullable_column->get_null_map_data().push_back(0);
+ }
+ }
+
+ if (dst_col_ptr->is_bitmap()) {
+ auto& bitmap_column = reinterpret_cast<vectorized::ColumnBitmap&>(*dst_col_ptr);
+ for (size_t i = 0; i < max_fetch; i++, _cur_idx++) {
+ const uint32_t start_offset = offset(_cur_idx);
+ uint32_t len = offset(_cur_idx + 1) - start_offset;
+
+ bitmap_column.insert_default();
+ BitmapValue* pvalue = &bitmap_column.get_element(bitmap_column.size() - 1);
+ if (len != 0) {
+ BitmapValue value;
+ value.deserialize(&_data[start_offset]);
+ *pvalue = std::move(value);
Review comment:
why not use pvalue->deserialize() directly?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] zuochunwei commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
zuochunwei commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781958858
##########
File path: be/src/olap/rowset/segment_v2/segment_iterator.cpp
##########
@@ -581,9 +586,358 @@ Status SegmentIterator::next_batch(RowBlockV2* block) {
return Status::OK();
}
+/* ---------------------- for vecterization implementation ---------------------- */
+
+// todo(wb) need a UT here
+void SegmentIterator::_vec_init_lazy_materialization() {
+ _is_pred_column.resize(_schema.columns().size(), false);
+
+ std::set<ColumnId> pred_column_ids; // including short_cir_pred_col_id_set and vec_pred_col_id_set
+ _is_all_column_basic_type = true;
+ bool is_predicate_column_exists = false;
+ bool is_non_predicate_column_exists = false;
+
+ if (!_col_predicates.empty()) {
+ is_predicate_column_exists = true;
+
+ std::set<ColumnId> short_cir_pred_col_id_set; // using set for distinct cid
+ std::set<ColumnId> vec_pred_col_id_set;
+
+ for (auto predicate : _col_predicates) {
+ auto cid = predicate->column_id();
+ FieldType type = _schema.column(cid)->type();
+ _is_pred_column[cid] = true;
+ pred_column_ids.insert(cid);
+
+ // for date type which can not be executed in a vectorized way, using short circuit execution
+ if (type == OLAP_FIELD_TYPE_VARCHAR || type == OLAP_FIELD_TYPE_CHAR || type == OLAP_FIELD_TYPE_DECIMAL
+ || type == OLAP_FIELD_TYPE_DATE || predicate->is_in_predicate()) {
+ short_cir_pred_col_id_set.insert(cid);
+ _short_cir_eval_predicate.push_back(predicate);
+ _is_all_column_basic_type = false;
+ } else {
+ vec_pred_col_id_set.insert(predicate->column_id());
+ if (_pre_eval_block_predicate == nullptr) {
+ _pre_eval_block_predicate = new AndBlockColumnPredicate();
+ }
+ reinterpret_cast<MutilColumnBlockPredicate*>(_pre_eval_block_predicate)->add_column_predicate(new SingleColumnBlockPredicate(predicate));
+ }
+ }
+
+ std::set<ColumnId> del_cond_id_set;
+ _opts.delete_condition_predicates.get()->get_all_column_ids(del_cond_id_set);
+ short_cir_pred_col_id_set.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+ pred_column_ids.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+
+ if (_schema.column_ids().size() > pred_column_ids.size()) {
+ for (auto cid : _schema.column_ids()) {
+ if (!_is_pred_column[cid]) {
+ _non_predicate_columns.push_back(cid);
+ is_non_predicate_column_exists = true;
+ }
+ }
+ }
+
+ _vec_pred_column_ids.assign(vec_pred_col_id_set.cbegin(), vec_pred_col_id_set.cend());
+ _short_cir_pred_column_ids.assign(short_cir_pred_col_id_set.cbegin(), short_cir_pred_col_id_set.cend());
+ } else {
+ _is_all_column_basic_type = false;
+ is_non_predicate_column_exists = true;
+ for (auto cid : _schema.column_ids()) {
+ _non_predicate_columns.push_back(cid);
+ }
+ }
+
+ // note(wb) in following cases we disable lazy materialization
+ // case 1: when all column is basic type(is_all_column_basic_type = true)
+ // because we think `seek and read` cost > read page cost, lazy materialize may cause more `seek and read`, so disable it
+ // case 2: all column is predicate column
+ // case 3: all column is not predicate column
+ // todo(wb) need further research more lazy materialization rule, such as get more info from `statistics` for better decision
+ if (_is_all_column_basic_type) {
+ std::set<ColumnId> pred_set(_vec_pred_column_ids.begin(), _vec_pred_column_ids.end());
+ std::set<ColumnId> non_pred_set(_non_predicate_columns.begin(), _non_predicate_columns.end());
+
+ // when _is_all_column_basic_type = true, _first_read_column_ids should keep the same order with _schema.column_ids which stands for return column order
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (pred_set.find(cid) != pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ } else if (non_pred_set.find(cid) != non_pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ _is_pred_column[cid] = true; // in this case, non-predicate column should also be filtered by sel idx, so we regard it as pred columns
+ }
+ }
+
+ } else if (is_predicate_column_exists && !is_non_predicate_column_exists) {
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ } else if (!is_predicate_column_exists && is_non_predicate_column_exists) {
+ for (auto cid : _non_predicate_columns) {
+ _first_read_column_ids.push_back(cid);
+ }
+ } else {
+ _lazy_materialization_read = true;
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ }
+
+ // make _schema_block_id_map
+ _schema_block_id_map.resize(_schema.columns().size());
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ _schema_block_id_map[cid] = i;
+ }
+
+}
+
+Status SegmentIterator::_read_columns(const std::vector<ColumnId>& column_ids, vectorized::MutableColumns& column_block, size_t nrows) {
+ for (auto cid : column_ids) {
+ auto& column = column_block[cid];
+ size_t rows_read = nrows;
+ RETURN_IF_ERROR(_column_iterators[cid]->next_batch(&rows_read, column));
+ DCHECK_EQ(nrows, rows_read);
+ }
+ return Status::OK();
+}
+
+void SegmentIterator::_init_current_block(vectorized::Block* block, std::vector<vectorized::MutableColumnPtr>& current_columns) {
+ bool is_block_mem_reuse= block->mem_reuse();
+ if (is_block_mem_reuse) {
+ size_t column_to_keep = _schema.num_column_ids();
+ for (int i = block->columns() - 1; i >= column_to_keep; i--) {
+ block->erase(i);
+ }
+ block->clear_column_data();
+ } else { // pre fill output block here
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ auto* column_desc = _schema.columns()[cid];
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ if (column_desc->is_nullable()) {
+ block->insert({nullptr, std::make_shared<vectorized::DataTypeNullable>(std::move(data_type)), column_desc->name()});
+ } else {
+ block->insert({nullptr, std::move(data_type), column_desc->name()});
+ }
+ }
+ }
+
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (_is_pred_column[cid]) { //todo(wb) maybe we can relase it after output block
+ current_columns[cid]->clear();
+ } else { // non-predicate column
+ auto &column_desc = _schema.columns()[cid];
+ if (is_block_mem_reuse) {
+ current_columns[cid] = std::move(*block->get_by_position(i).column).mutate();
+ } else {
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ if (column_desc->is_nullable()) {
+ current_columns[cid] = doris::vectorized::ColumnNullable::create(
+ std::move(data_type->create_column()), doris::vectorized::ColumnUInt8::create());
+ } else {
+ current_columns[cid] = data_type->create_column();
+ }
+ }
+ if (column_desc->type() == OLAP_FIELD_TYPE_DATE) {
+ current_columns[cid]->set_date_type();
+ } else if (column_desc->type() == OLAP_FIELD_TYPE_DATETIME) {
+ current_columns[cid]->set_datetime_type();
+ }
+ }
+ }
+}
+
+void SegmentIterator::_output_non_pred_columns(vectorized::Block* block, bool is_block_mem_reuse) {
+ for (auto cid : _non_predicate_columns) {
+ block->replace_by_position(_schema_block_id_map[cid], std::move(_current_return_columns[cid]));
+ }
+ }
+
+void SegmentIterator::_output_column_by_sel_idx(vectorized::Block* block, std::vector<ColumnId> columnIds,
+ uint16_t* sel_rowid_idx, uint16_t select_size, bool is_block_mem_reuse) {
+ for (auto cid : columnIds) {
+ auto &column_ptr = _current_return_columns[cid];
+ if (is_block_mem_reuse) {
+ column_ptr->filter_by_selector(sel_rowid_idx, select_size,
+ &block->get_by_position(_schema_block_id_map[cid]).column);
+ } else {
+ block->replace_by_position(_schema_block_id_map[cid],
+ (*column_ptr).get_ptr()->filter_by_selector(sel_rowid_idx, select_size));
+ }
+ }
+ }
+
+
+Status SegmentIterator::_read_columns_by_index(uint32_t nrows_read_limit, uint32_t& nrows_read, bool set_block_rowid) {
+ do {
+ uint32_t range_from;
+ uint32_t range_to;
+ bool has_next_range =
+ _range_iter->next_range(nrows_read_limit - nrows_read, &range_from, &range_to);
+ if (!has_next_range) {
+ break;
+ }
+ if (_cur_rowid == 0 || _cur_rowid != range_from) {
+ _cur_rowid = range_from;
+ RETURN_IF_ERROR(_seek_columns(_first_read_column_ids, _cur_rowid));
+ }
+ size_t rows_to_read = range_to - range_from;
+ RETURN_IF_ERROR(_read_columns(_first_read_column_ids, _current_return_columns, rows_to_read));
+ _cur_rowid += rows_to_read;
+ if (set_block_rowid) {
+ for (uint32_t rid = range_from; rid < range_to; rid++) {
+ _block_rowids[nrows_read++] = rid;
+ }
+ } else {
+ nrows_read += rows_to_read;
+ }
+ } while (nrows_read < nrows_read_limit);
+ return Status::OK();
+}
+
+void SegmentIterator::_evaluate_vectorization_predicate(uint16_t* sel_rowid_idx, uint16_t& selected_size) {
+ uint16_t new_size = 0;
+ if (_vec_pred_column_ids.size() == 0) {
+ for (uint32_t i = 0; i < selected_size; ++i) {
+ sel_rowid_idx[new_size++] = i;
+ }
+ return;
+ }
+
+ uint16_t original_size = selected_size;
+ bool ret_flags[selected_size];
+ memset(ret_flags, 1, selected_size);
+ _pre_eval_block_predicate->evaluate_vec(_current_return_columns, selected_size, ret_flags);
+
+ for (uint32_t i = 0; i < selected_size; ++i) {
+ if (ret_flags[i]) {
+ sel_rowid_idx[new_size++] = i;
+ }
+ }
+
+ _opts.stats->rows_vec_cond_filtered += original_size - new_size;
+ selected_size = new_size;
+}
+
+void SegmentIterator::_evaluate_short_circuit_predicate(uint16_t* vec_sel_rowid_idx, uint16_t* selected_size_ptr) {
+ if (_short_cir_pred_column_ids.size() == 0) {
+ return;
+ }
+
+ for (auto column_predicate : _short_cir_eval_predicate) {
+ auto column_id = column_predicate->column_id();
+ auto& short_cir_column = _current_return_columns[column_id];
+ column_predicate->evaluate(*short_cir_column, vec_sel_rowid_idx, selected_size_ptr);
+ }
+
+ // evaluate delete condition
+ _opts.delete_condition_predicates->evaluate(_current_return_columns, vec_sel_rowid_idx, selected_size_ptr);
+}
+
+void SegmentIterator::_read_columns_by_rowids(std::vector<ColumnId>& read_column_ids, std::vector<rowid_t>& rowid_vector,
+ uint16_t* sel_rowid_idx, size_t select_size, vectorized::MutableColumns* mutable_columns) {
+ size_t start_idx = 0;
+ while (start_idx < select_size) {
+ size_t end_idx = start_idx + 1;
+ while (end_idx < select_size && (rowid_vector[sel_rowid_idx[end_idx - 1]] == rowid_vector[sel_rowid_idx[end_idx]] - 1)) {
+ end_idx++;
+ }
+ size_t range = end_idx - start_idx;
+ _seek_columns(read_column_ids, rowid_vector[sel_rowid_idx[start_idx]]);
+ _read_columns(read_column_ids, *mutable_columns, range);
+ start_idx += range;
+ }
+}
+
Status SegmentIterator::next_batch(vectorized::Block* block) {
- //TODO
- return Status::NotSupported("not implement now");
+ bool is_mem_reuse = block->mem_reuse();
+ SCOPED_RAW_TIMER(&_opts.stats->block_load_ns);
+ if (UNLIKELY(!_inited)) {
+ RETURN_IF_ERROR(_init(true));
Review comment:
conditionly init is not a good practice although this usage is applied frequently
separating init from next_batch is more reasonable because these two methods do absolutely different things
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] zuochunwei commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
zuochunwei commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781790246
##########
File path: be/src/vec/columns/column_nullable.h
##########
@@ -130,7 +130,13 @@ class ColumnNullable final : public COWHelper<IColumn, ColumnNullable> {
return false;
}
+ bool is_date_type() override { return get_nested_column().is_date_type(); }
Review comment:
the same problem to above
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] wangbo commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
wangbo commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r782776606
##########
File path: be/src/olap/rowset/segment_v2/segment_iterator.cpp
##########
@@ -581,9 +586,358 @@ Status SegmentIterator::next_batch(RowBlockV2* block) {
return Status::OK();
}
+/* ---------------------- for vecterization implementation ---------------------- */
+
+// todo(wb) need a UT here
+void SegmentIterator::_vec_init_lazy_materialization() {
+ _is_pred_column.resize(_schema.columns().size(), false);
+
+ std::set<ColumnId> pred_column_ids; // including short_cir_pred_col_id_set and vec_pred_col_id_set
+ _is_all_column_basic_type = true;
+ bool is_predicate_column_exists = false;
+ bool is_non_predicate_column_exists = false;
+
+ if (!_col_predicates.empty()) {
+ is_predicate_column_exists = true;
+
+ std::set<ColumnId> short_cir_pred_col_id_set; // using set for distinct cid
+ std::set<ColumnId> vec_pred_col_id_set;
+
+ for (auto predicate : _col_predicates) {
+ auto cid = predicate->column_id();
+ FieldType type = _schema.column(cid)->type();
+ _is_pred_column[cid] = true;
+ pred_column_ids.insert(cid);
+
+ // for date type which can not be executed in a vectorized way, using short circuit execution
+ if (type == OLAP_FIELD_TYPE_VARCHAR || type == OLAP_FIELD_TYPE_CHAR || type == OLAP_FIELD_TYPE_DECIMAL
+ || type == OLAP_FIELD_TYPE_DATE || predicate->is_in_predicate()) {
+ short_cir_pred_col_id_set.insert(cid);
+ _short_cir_eval_predicate.push_back(predicate);
+ _is_all_column_basic_type = false;
+ } else {
+ vec_pred_col_id_set.insert(predicate->column_id());
+ if (_pre_eval_block_predicate == nullptr) {
+ _pre_eval_block_predicate = new AndBlockColumnPredicate();
+ }
+ reinterpret_cast<MutilColumnBlockPredicate*>(_pre_eval_block_predicate)->add_column_predicate(new SingleColumnBlockPredicate(predicate));
+ }
+ }
+
+ std::set<ColumnId> del_cond_id_set;
+ _opts.delete_condition_predicates.get()->get_all_column_ids(del_cond_id_set);
+ short_cir_pred_col_id_set.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+ pred_column_ids.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+
+ if (_schema.column_ids().size() > pred_column_ids.size()) {
+ for (auto cid : _schema.column_ids()) {
+ if (!_is_pred_column[cid]) {
+ _non_predicate_columns.push_back(cid);
+ is_non_predicate_column_exists = true;
+ }
+ }
+ }
+
+ _vec_pred_column_ids.assign(vec_pred_col_id_set.cbegin(), vec_pred_col_id_set.cend());
+ _short_cir_pred_column_ids.assign(short_cir_pred_col_id_set.cbegin(), short_cir_pred_col_id_set.cend());
+ } else {
+ _is_all_column_basic_type = false;
+ is_non_predicate_column_exists = true;
+ for (auto cid : _schema.column_ids()) {
+ _non_predicate_columns.push_back(cid);
+ }
+ }
+
+ // note(wb) in following cases we disable lazy materialization
+ // case 1: when all column is basic type(is_all_column_basic_type = true)
+ // because we think `seek and read` cost > read page cost, lazy materialize may cause more `seek and read`, so disable it
+ // case 2: all column is predicate column
+ // case 3: all column is not predicate column
+ // todo(wb) need further research more lazy materialization rule, such as get more info from `statistics` for better decision
+ if (_is_all_column_basic_type) {
+ std::set<ColumnId> pred_set(_vec_pred_column_ids.begin(), _vec_pred_column_ids.end());
+ std::set<ColumnId> non_pred_set(_non_predicate_columns.begin(), _non_predicate_columns.end());
+
+ // when _is_all_column_basic_type = true, _first_read_column_ids should keep the same order with _schema.column_ids which stands for return column order
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (pred_set.find(cid) != pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ } else if (non_pred_set.find(cid) != non_pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ _is_pred_column[cid] = true; // in this case, non-predicate column should also be filtered by sel idx, so we regard it as pred columns
+ }
+ }
+
+ } else if (is_predicate_column_exists && !is_non_predicate_column_exists) {
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ } else if (!is_predicate_column_exists && is_non_predicate_column_exists) {
+ for (auto cid : _non_predicate_columns) {
+ _first_read_column_ids.push_back(cid);
+ }
+ } else {
+ _lazy_materialization_read = true;
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ }
+
+ // make _schema_block_id_map
+ _schema_block_id_map.resize(_schema.columns().size());
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ _schema_block_id_map[cid] = i;
+ }
+
+}
+
+Status SegmentIterator::_read_columns(const std::vector<ColumnId>& column_ids, vectorized::MutableColumns& column_block, size_t nrows) {
+ for (auto cid : column_ids) {
+ auto& column = column_block[cid];
+ size_t rows_read = nrows;
+ RETURN_IF_ERROR(_column_iterators[cid]->next_batch(&rows_read, column));
+ DCHECK_EQ(nrows, rows_read);
+ }
+ return Status::OK();
+}
+
+void SegmentIterator::_init_current_block(vectorized::Block* block, std::vector<vectorized::MutableColumnPtr>& current_columns) {
+ bool is_block_mem_reuse= block->mem_reuse();
+ if (is_block_mem_reuse) {
+ size_t column_to_keep = _schema.num_column_ids();
+ for (int i = block->columns() - 1; i >= column_to_keep; i--) {
+ block->erase(i);
+ }
+ block->clear_column_data();
+ } else { // pre fill output block here
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ auto* column_desc = _schema.columns()[cid];
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ if (column_desc->is_nullable()) {
+ block->insert({nullptr, std::make_shared<vectorized::DataTypeNullable>(std::move(data_type)), column_desc->name()});
+ } else {
+ block->insert({nullptr, std::move(data_type), column_desc->name()});
+ }
+ }
+ }
+
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (_is_pred_column[cid]) { //todo(wb) maybe we can relase it after output block
+ current_columns[cid]->clear();
+ } else { // non-predicate column
+ auto &column_desc = _schema.columns()[cid];
+ if (is_block_mem_reuse) {
+ current_columns[cid] = std::move(*block->get_by_position(i).column).mutate();
+ } else {
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ if (column_desc->is_nullable()) {
+ current_columns[cid] = doris::vectorized::ColumnNullable::create(
+ std::move(data_type->create_column()), doris::vectorized::ColumnUInt8::create());
+ } else {
+ current_columns[cid] = data_type->create_column();
+ }
+ }
+ if (column_desc->type() == OLAP_FIELD_TYPE_DATE) {
+ current_columns[cid]->set_date_type();
+ } else if (column_desc->type() == OLAP_FIELD_TYPE_DATETIME) {
+ current_columns[cid]->set_datetime_type();
+ }
+ }
+ }
+}
+
+void SegmentIterator::_output_non_pred_columns(vectorized::Block* block, bool is_block_mem_reuse) {
+ for (auto cid : _non_predicate_columns) {
+ block->replace_by_position(_schema_block_id_map[cid], std::move(_current_return_columns[cid]));
+ }
+ }
+
+void SegmentIterator::_output_column_by_sel_idx(vectorized::Block* block, std::vector<ColumnId> columnIds,
+ uint16_t* sel_rowid_idx, uint16_t select_size, bool is_block_mem_reuse) {
+ for (auto cid : columnIds) {
+ auto &column_ptr = _current_return_columns[cid];
+ if (is_block_mem_reuse) {
+ column_ptr->filter_by_selector(sel_rowid_idx, select_size,
+ &block->get_by_position(_schema_block_id_map[cid]).column);
+ } else {
+ block->replace_by_position(_schema_block_id_map[cid],
+ (*column_ptr).get_ptr()->filter_by_selector(sel_rowid_idx, select_size));
+ }
+ }
+ }
+
+
+Status SegmentIterator::_read_columns_by_index(uint32_t nrows_read_limit, uint32_t& nrows_read, bool set_block_rowid) {
+ do {
+ uint32_t range_from;
+ uint32_t range_to;
+ bool has_next_range =
+ _range_iter->next_range(nrows_read_limit - nrows_read, &range_from, &range_to);
+ if (!has_next_range) {
+ break;
+ }
+ if (_cur_rowid == 0 || _cur_rowid != range_from) {
+ _cur_rowid = range_from;
+ RETURN_IF_ERROR(_seek_columns(_first_read_column_ids, _cur_rowid));
+ }
+ size_t rows_to_read = range_to - range_from;
+ RETURN_IF_ERROR(_read_columns(_first_read_column_ids, _current_return_columns, rows_to_read));
+ _cur_rowid += rows_to_read;
+ if (set_block_rowid) {
+ for (uint32_t rid = range_from; rid < range_to; rid++) {
+ _block_rowids[nrows_read++] = rid;
+ }
+ } else {
+ nrows_read += rows_to_read;
+ }
+ } while (nrows_read < nrows_read_limit);
+ return Status::OK();
+}
+
+void SegmentIterator::_evaluate_vectorization_predicate(uint16_t* sel_rowid_idx, uint16_t& selected_size) {
+ uint16_t new_size = 0;
+ if (_vec_pred_column_ids.size() == 0) {
+ for (uint32_t i = 0; i < selected_size; ++i) {
+ sel_rowid_idx[new_size++] = i;
+ }
+ return;
+ }
+
+ uint16_t original_size = selected_size;
+ bool ret_flags[selected_size];
+ memset(ret_flags, 1, selected_size);
+ _pre_eval_block_predicate->evaluate_vec(_current_return_columns, selected_size, ret_flags);
+
+ for (uint32_t i = 0; i < selected_size; ++i) {
+ if (ret_flags[i]) {
+ sel_rowid_idx[new_size++] = i;
+ }
+ }
+
+ _opts.stats->rows_vec_cond_filtered += original_size - new_size;
+ selected_size = new_size;
+}
+
+void SegmentIterator::_evaluate_short_circuit_predicate(uint16_t* vec_sel_rowid_idx, uint16_t* selected_size_ptr) {
+ if (_short_cir_pred_column_ids.size() == 0) {
+ return;
+ }
+
+ for (auto column_predicate : _short_cir_eval_predicate) {
+ auto column_id = column_predicate->column_id();
+ auto& short_cir_column = _current_return_columns[column_id];
+ column_predicate->evaluate(*short_cir_column, vec_sel_rowid_idx, selected_size_ptr);
+ }
+
+ // evaluate delete condition
+ _opts.delete_condition_predicates->evaluate(_current_return_columns, vec_sel_rowid_idx, selected_size_ptr);
+}
+
+void SegmentIterator::_read_columns_by_rowids(std::vector<ColumnId>& read_column_ids, std::vector<rowid_t>& rowid_vector,
+ uint16_t* sel_rowid_idx, size_t select_size, vectorized::MutableColumns* mutable_columns) {
+ size_t start_idx = 0;
+ while (start_idx < select_size) {
+ size_t end_idx = start_idx + 1;
+ while (end_idx < select_size && (rowid_vector[sel_rowid_idx[end_idx - 1]] == rowid_vector[sel_rowid_idx[end_idx]] - 1)) {
+ end_idx++;
+ }
+ size_t range = end_idx - start_idx;
+ _seek_columns(read_column_ids, rowid_vector[sel_rowid_idx[start_idx]]);
+ _read_columns(read_column_ids, *mutable_columns, range);
+ start_idx += range;
+ }
+}
+
Status SegmentIterator::next_batch(vectorized::Block* block) {
- //TODO
- return Status::NotSupported("not implement now");
+ bool is_mem_reuse = block->mem_reuse();
+ SCOPED_RAW_TIMER(&_opts.stats->block_load_ns);
+ if (UNLIKELY(!_inited)) {
+ RETURN_IF_ERROR(_init(true));
+ _inited = true;
+ if (_vec_pred_column_ids.size() > 0 || _short_cir_pred_column_ids.size() > 0) {
+ _block_rowids.reserve(_opts.block_row_max);
+ }
+ _current_return_columns.resize(_schema.columns().size());
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (_is_pred_column[cid]) {
+ auto& column_desc = _schema.columns()[cid];
+ _current_return_columns[cid] = Schema::get_predicate_column_nullable_ptr(column_desc->type(), column_desc->is_nullable());
+ _current_return_columns[cid]->reserve(_opts.block_row_max);
+ }
+ }
+ }
+
+ _init_current_block(block, _current_return_columns);
+
+ uint32_t nrows_read = 0;
+ uint32_t nrows_read_limit = _opts.block_row_max;
+ _read_columns_by_index(nrows_read_limit, nrows_read, _col_predicates.size() > 0);
+
+ _opts.stats->blocks_load += 1;
+ _opts.stats->raw_rows_read += nrows_read;
+
+ if (nrows_read == 0) {
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ // todo(wb) abstract make column where
+ if (!_is_pred_column[cid]) { // non-predicate
+ block->replace_by_position(i, std::move(_current_return_columns[cid]));
+ } else { // predicate
+ if (!is_mem_reuse) {
+ auto* column_desc = _schema.columns()[cid];
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ block->replace_by_position(i, data_type->create_column());
+ }
+ }
+ // not sure whether block is clear before enter segmentIter, so clear it here.
+ if (is_mem_reuse) {
Review comment:
You are right, but this is just a defensive strategy.
What you talk about should be considered after this PR merged, that's not this PR wish to solve.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] zuochunwei commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
zuochunwei commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781966568
##########
File path: be/src/olap/rowset/segment_v2/segment_iterator.cpp
##########
@@ -581,9 +586,358 @@ Status SegmentIterator::next_batch(RowBlockV2* block) {
return Status::OK();
}
+/* ---------------------- for vecterization implementation ---------------------- */
+
+// todo(wb) need a UT here
+void SegmentIterator::_vec_init_lazy_materialization() {
+ _is_pred_column.resize(_schema.columns().size(), false);
+
+ std::set<ColumnId> pred_column_ids; // including short_cir_pred_col_id_set and vec_pred_col_id_set
+ _is_all_column_basic_type = true;
+ bool is_predicate_column_exists = false;
+ bool is_non_predicate_column_exists = false;
+
+ if (!_col_predicates.empty()) {
+ is_predicate_column_exists = true;
+
+ std::set<ColumnId> short_cir_pred_col_id_set; // using set for distinct cid
+ std::set<ColumnId> vec_pred_col_id_set;
+
+ for (auto predicate : _col_predicates) {
+ auto cid = predicate->column_id();
+ FieldType type = _schema.column(cid)->type();
+ _is_pred_column[cid] = true;
+ pred_column_ids.insert(cid);
+
+ // for date type which can not be executed in a vectorized way, using short circuit execution
+ if (type == OLAP_FIELD_TYPE_VARCHAR || type == OLAP_FIELD_TYPE_CHAR || type == OLAP_FIELD_TYPE_DECIMAL
+ || type == OLAP_FIELD_TYPE_DATE || predicate->is_in_predicate()) {
+ short_cir_pred_col_id_set.insert(cid);
+ _short_cir_eval_predicate.push_back(predicate);
+ _is_all_column_basic_type = false;
+ } else {
+ vec_pred_col_id_set.insert(predicate->column_id());
+ if (_pre_eval_block_predicate == nullptr) {
+ _pre_eval_block_predicate = new AndBlockColumnPredicate();
+ }
+ reinterpret_cast<MutilColumnBlockPredicate*>(_pre_eval_block_predicate)->add_column_predicate(new SingleColumnBlockPredicate(predicate));
+ }
+ }
+
+ std::set<ColumnId> del_cond_id_set;
+ _opts.delete_condition_predicates.get()->get_all_column_ids(del_cond_id_set);
+ short_cir_pred_col_id_set.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+ pred_column_ids.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+
+ if (_schema.column_ids().size() > pred_column_ids.size()) {
+ for (auto cid : _schema.column_ids()) {
+ if (!_is_pred_column[cid]) {
+ _non_predicate_columns.push_back(cid);
+ is_non_predicate_column_exists = true;
+ }
+ }
+ }
+
+ _vec_pred_column_ids.assign(vec_pred_col_id_set.cbegin(), vec_pred_col_id_set.cend());
+ _short_cir_pred_column_ids.assign(short_cir_pred_col_id_set.cbegin(), short_cir_pred_col_id_set.cend());
+ } else {
+ _is_all_column_basic_type = false;
+ is_non_predicate_column_exists = true;
+ for (auto cid : _schema.column_ids()) {
+ _non_predicate_columns.push_back(cid);
+ }
+ }
+
+ // note(wb) in following cases we disable lazy materialization
+ // case 1: when all column is basic type(is_all_column_basic_type = true)
+ // because we think `seek and read` cost > read page cost, lazy materialize may cause more `seek and read`, so disable it
+ // case 2: all column is predicate column
+ // case 3: all column is not predicate column
+ // todo(wb) need further research more lazy materialization rule, such as get more info from `statistics` for better decision
+ if (_is_all_column_basic_type) {
+ std::set<ColumnId> pred_set(_vec_pred_column_ids.begin(), _vec_pred_column_ids.end());
+ std::set<ColumnId> non_pred_set(_non_predicate_columns.begin(), _non_predicate_columns.end());
+
+ // when _is_all_column_basic_type = true, _first_read_column_ids should keep the same order with _schema.column_ids which stands for return column order
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (pred_set.find(cid) != pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ } else if (non_pred_set.find(cid) != non_pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ _is_pred_column[cid] = true; // in this case, non-predicate column should also be filtered by sel idx, so we regard it as pred columns
+ }
+ }
+
+ } else if (is_predicate_column_exists && !is_non_predicate_column_exists) {
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ } else if (!is_predicate_column_exists && is_non_predicate_column_exists) {
+ for (auto cid : _non_predicate_columns) {
+ _first_read_column_ids.push_back(cid);
+ }
+ } else {
+ _lazy_materialization_read = true;
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ }
+
+ // make _schema_block_id_map
+ _schema_block_id_map.resize(_schema.columns().size());
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ _schema_block_id_map[cid] = i;
+ }
+
+}
+
+Status SegmentIterator::_read_columns(const std::vector<ColumnId>& column_ids, vectorized::MutableColumns& column_block, size_t nrows) {
+ for (auto cid : column_ids) {
+ auto& column = column_block[cid];
+ size_t rows_read = nrows;
+ RETURN_IF_ERROR(_column_iterators[cid]->next_batch(&rows_read, column));
+ DCHECK_EQ(nrows, rows_read);
+ }
+ return Status::OK();
+}
+
+void SegmentIterator::_init_current_block(vectorized::Block* block, std::vector<vectorized::MutableColumnPtr>& current_columns) {
+ bool is_block_mem_reuse= block->mem_reuse();
+ if (is_block_mem_reuse) {
+ size_t column_to_keep = _schema.num_column_ids();
+ for (int i = block->columns() - 1; i >= column_to_keep; i--) {
+ block->erase(i);
+ }
+ block->clear_column_data();
Review comment:
use block->clear_column_data(_schema.num_column_ids()) is better!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] zuochunwei commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
zuochunwei commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781978307
##########
File path: be/src/olap/rowset/segment_v2/segment_iterator.cpp
##########
@@ -581,9 +586,358 @@ Status SegmentIterator::next_batch(RowBlockV2* block) {
return Status::OK();
}
+/* ---------------------- for vecterization implementation ---------------------- */
+
+// todo(wb) need a UT here
+void SegmentIterator::_vec_init_lazy_materialization() {
+ _is_pred_column.resize(_schema.columns().size(), false);
+
+ std::set<ColumnId> pred_column_ids; // including short_cir_pred_col_id_set and vec_pred_col_id_set
+ _is_all_column_basic_type = true;
+ bool is_predicate_column_exists = false;
+ bool is_non_predicate_column_exists = false;
+
+ if (!_col_predicates.empty()) {
+ is_predicate_column_exists = true;
+
+ std::set<ColumnId> short_cir_pred_col_id_set; // using set for distinct cid
+ std::set<ColumnId> vec_pred_col_id_set;
+
+ for (auto predicate : _col_predicates) {
+ auto cid = predicate->column_id();
+ FieldType type = _schema.column(cid)->type();
+ _is_pred_column[cid] = true;
+ pred_column_ids.insert(cid);
+
+ // for date type which can not be executed in a vectorized way, using short circuit execution
+ if (type == OLAP_FIELD_TYPE_VARCHAR || type == OLAP_FIELD_TYPE_CHAR || type == OLAP_FIELD_TYPE_DECIMAL
+ || type == OLAP_FIELD_TYPE_DATE || predicate->is_in_predicate()) {
+ short_cir_pred_col_id_set.insert(cid);
+ _short_cir_eval_predicate.push_back(predicate);
+ _is_all_column_basic_type = false;
+ } else {
+ vec_pred_col_id_set.insert(predicate->column_id());
+ if (_pre_eval_block_predicate == nullptr) {
+ _pre_eval_block_predicate = new AndBlockColumnPredicate();
+ }
+ reinterpret_cast<MutilColumnBlockPredicate*>(_pre_eval_block_predicate)->add_column_predicate(new SingleColumnBlockPredicate(predicate));
+ }
+ }
+
+ std::set<ColumnId> del_cond_id_set;
+ _opts.delete_condition_predicates.get()->get_all_column_ids(del_cond_id_set);
+ short_cir_pred_col_id_set.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+ pred_column_ids.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+
+ if (_schema.column_ids().size() > pred_column_ids.size()) {
+ for (auto cid : _schema.column_ids()) {
+ if (!_is_pred_column[cid]) {
+ _non_predicate_columns.push_back(cid);
+ is_non_predicate_column_exists = true;
+ }
+ }
+ }
+
+ _vec_pred_column_ids.assign(vec_pred_col_id_set.cbegin(), vec_pred_col_id_set.cend());
+ _short_cir_pred_column_ids.assign(short_cir_pred_col_id_set.cbegin(), short_cir_pred_col_id_set.cend());
+ } else {
+ _is_all_column_basic_type = false;
+ is_non_predicate_column_exists = true;
+ for (auto cid : _schema.column_ids()) {
+ _non_predicate_columns.push_back(cid);
+ }
+ }
+
+ // note(wb) in following cases we disable lazy materialization
+ // case 1: when all column is basic type(is_all_column_basic_type = true)
+ // because we think `seek and read` cost > read page cost, lazy materialize may cause more `seek and read`, so disable it
+ // case 2: all column is predicate column
+ // case 3: all column is not predicate column
+ // todo(wb) need further research more lazy materialization rule, such as get more info from `statistics` for better decision
+ if (_is_all_column_basic_type) {
+ std::set<ColumnId> pred_set(_vec_pred_column_ids.begin(), _vec_pred_column_ids.end());
+ std::set<ColumnId> non_pred_set(_non_predicate_columns.begin(), _non_predicate_columns.end());
+
+ // when _is_all_column_basic_type = true, _first_read_column_ids should keep the same order with _schema.column_ids which stands for return column order
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (pred_set.find(cid) != pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ } else if (non_pred_set.find(cid) != non_pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ _is_pred_column[cid] = true; // in this case, non-predicate column should also be filtered by sel idx, so we regard it as pred columns
+ }
+ }
+
+ } else if (is_predicate_column_exists && !is_non_predicate_column_exists) {
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ } else if (!is_predicate_column_exists && is_non_predicate_column_exists) {
+ for (auto cid : _non_predicate_columns) {
+ _first_read_column_ids.push_back(cid);
+ }
+ } else {
+ _lazy_materialization_read = true;
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ }
+
+ // make _schema_block_id_map
+ _schema_block_id_map.resize(_schema.columns().size());
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ _schema_block_id_map[cid] = i;
+ }
+
+}
+
+Status SegmentIterator::_read_columns(const std::vector<ColumnId>& column_ids, vectorized::MutableColumns& column_block, size_t nrows) {
+ for (auto cid : column_ids) {
+ auto& column = column_block[cid];
+ size_t rows_read = nrows;
+ RETURN_IF_ERROR(_column_iterators[cid]->next_batch(&rows_read, column));
+ DCHECK_EQ(nrows, rows_read);
+ }
+ return Status::OK();
+}
+
+void SegmentIterator::_init_current_block(vectorized::Block* block, std::vector<vectorized::MutableColumnPtr>& current_columns) {
Review comment:
why pass member data _current_return_columns as member function argument?
why not use _current_return_columns directly in _init_current_block
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] zuochunwei commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
zuochunwei commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781783797
##########
File path: be/src/olap/column_predicate.h
##########
@@ -69,6 +69,8 @@ class ColumnPredicate {
virtual void evaluate_vec(vectorized::IColumn& column, uint16_t size, bool* flags) const {};
uint32_t column_id() const { return _column_id; }
+ virtual bool is_in_predicate() { return false; }
Review comment:
is_in_predicate should be declared as const because it seems read-only
##########
File path: be/src/olap/rowset/segment_v2/bitshuffle_page.h
##########
@@ -359,17 +361,28 @@ class BitShufflePageDecoder : public PageDecoder {
int begin = _cur_index;
int end = _cur_index + max_fetch;
-
+
+ auto* dst_col_ptr = dst.get();
+ if (dst->is_nullable()) {
+ auto nullable_column = assert_cast<vectorized::ColumnNullable*>(dst.get());
+ dst_col_ptr = nullable_column->get_nested_column_ptr().get();
+
+ // fill null bitmap here, not null;
+ for (int j = begin; j < end; j++) {
Review comment:
consider using add_num_element instead
##########
File path: be/src/vec/columns/column_nullable.h
##########
@@ -130,7 +130,13 @@ class ColumnNullable final : public COWHelper<IColumn, ColumnNullable> {
return false;
}
+ bool is_date_type() override { return get_nested_column().is_date_type(); }
Review comment:
same problem with above
##########
File path: be/src/vec/columns/column.h
##########
@@ -411,10 +413,15 @@ class IColumn : public COW<IColumn> {
// only used in ColumnNullable replace_column_data
virtual void replace_column_data_default(size_t self_row = 0) = 0;
- bool is_date_type() { return is_date; }
+ virtual bool is_date_type() { return is_date; }
Review comment:
is_xxx should be marked as const
##########
File path: be/src/olap/schema.cpp
##########
@@ -147,4 +155,57 @@ vectorized::DataTypePtr Schema::get_data_type_ptr(FieldType type) {
return nullptr;
}
+vectorized::IColumn::MutablePtr Schema::get_predicate_column_nullable_ptr(FieldType type, bool is_null) {
+ vectorized::IColumn::MutablePtr ptr = Schema::get_predicate_column_ptr(type);
+ if (is_null) {
+ return doris::vectorized::ColumnNullable::create(std::move(ptr), doris::vectorized::ColumnUInt8::create());
+ }
+ return ptr;
+}
+
+vectorized::IColumn::MutablePtr Schema::get_predicate_column_ptr(FieldType type) {
+ switch (type) {
+ case OLAP_FIELD_TYPE_TINYINT:
+ return doris::vectorized::PredicateColumnType<doris::vectorized::Int8>::create();
Review comment:
too much switch type case xxx, i have seen many times such functions, building a mapping may a good choice.
template technology may be useful to satisfied this need
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] HappenLee merged pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
HappenLee merged pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] wangbo commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
wangbo commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r782775077
##########
File path: be/src/olap/rowset/segment_v2/segment_iterator.cpp
##########
@@ -581,9 +586,358 @@ Status SegmentIterator::next_batch(RowBlockV2* block) {
return Status::OK();
}
+/* ---------------------- for vecterization implementation ---------------------- */
+
+// todo(wb) need a UT here
+void SegmentIterator::_vec_init_lazy_materialization() {
+ _is_pred_column.resize(_schema.columns().size(), false);
+
+ std::set<ColumnId> pred_column_ids; // including short_cir_pred_col_id_set and vec_pred_col_id_set
+ _is_all_column_basic_type = true;
+ bool is_predicate_column_exists = false;
+ bool is_non_predicate_column_exists = false;
+
+ if (!_col_predicates.empty()) {
+ is_predicate_column_exists = true;
+
+ std::set<ColumnId> short_cir_pred_col_id_set; // using set for distinct cid
+ std::set<ColumnId> vec_pred_col_id_set;
+
+ for (auto predicate : _col_predicates) {
+ auto cid = predicate->column_id();
+ FieldType type = _schema.column(cid)->type();
+ _is_pred_column[cid] = true;
+ pred_column_ids.insert(cid);
+
+ // for date type which can not be executed in a vectorized way, using short circuit execution
+ if (type == OLAP_FIELD_TYPE_VARCHAR || type == OLAP_FIELD_TYPE_CHAR || type == OLAP_FIELD_TYPE_DECIMAL
+ || type == OLAP_FIELD_TYPE_DATE || predicate->is_in_predicate()) {
+ short_cir_pred_col_id_set.insert(cid);
+ _short_cir_eval_predicate.push_back(predicate);
+ _is_all_column_basic_type = false;
+ } else {
+ vec_pred_col_id_set.insert(predicate->column_id());
+ if (_pre_eval_block_predicate == nullptr) {
+ _pre_eval_block_predicate = new AndBlockColumnPredicate();
+ }
+ reinterpret_cast<MutilColumnBlockPredicate*>(_pre_eval_block_predicate)->add_column_predicate(new SingleColumnBlockPredicate(predicate));
+ }
+ }
+
+ std::set<ColumnId> del_cond_id_set;
+ _opts.delete_condition_predicates.get()->get_all_column_ids(del_cond_id_set);
+ short_cir_pred_col_id_set.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+ pred_column_ids.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+
+ if (_schema.column_ids().size() > pred_column_ids.size()) {
+ for (auto cid : _schema.column_ids()) {
+ if (!_is_pred_column[cid]) {
+ _non_predicate_columns.push_back(cid);
+ is_non_predicate_column_exists = true;
+ }
+ }
+ }
+
+ _vec_pred_column_ids.assign(vec_pred_col_id_set.cbegin(), vec_pred_col_id_set.cend());
+ _short_cir_pred_column_ids.assign(short_cir_pred_col_id_set.cbegin(), short_cir_pred_col_id_set.cend());
+ } else {
+ _is_all_column_basic_type = false;
+ is_non_predicate_column_exists = true;
+ for (auto cid : _schema.column_ids()) {
+ _non_predicate_columns.push_back(cid);
+ }
+ }
+
+ // note(wb) in following cases we disable lazy materialization
+ // case 1: when all column is basic type(is_all_column_basic_type = true)
+ // because we think `seek and read` cost > read page cost, lazy materialize may cause more `seek and read`, so disable it
+ // case 2: all column is predicate column
+ // case 3: all column is not predicate column
+ // todo(wb) need further research more lazy materialization rule, such as get more info from `statistics` for better decision
+ if (_is_all_column_basic_type) {
+ std::set<ColumnId> pred_set(_vec_pred_column_ids.begin(), _vec_pred_column_ids.end());
+ std::set<ColumnId> non_pred_set(_non_predicate_columns.begin(), _non_predicate_columns.end());
+
+ // when _is_all_column_basic_type = true, _first_read_column_ids should keep the same order with _schema.column_ids which stands for return column order
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (pred_set.find(cid) != pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ } else if (non_pred_set.find(cid) != non_pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ _is_pred_column[cid] = true; // in this case, non-predicate column should also be filtered by sel idx, so we regard it as pred columns
+ }
+ }
+
+ } else if (is_predicate_column_exists && !is_non_predicate_column_exists) {
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ } else if (!is_predicate_column_exists && is_non_predicate_column_exists) {
+ for (auto cid : _non_predicate_columns) {
+ _first_read_column_ids.push_back(cid);
+ }
+ } else {
+ _lazy_materialization_read = true;
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ }
+
+ // make _schema_block_id_map
+ _schema_block_id_map.resize(_schema.columns().size());
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ _schema_block_id_map[cid] = i;
+ }
+
+}
+
+Status SegmentIterator::_read_columns(const std::vector<ColumnId>& column_ids, vectorized::MutableColumns& column_block, size_t nrows) {
+ for (auto cid : column_ids) {
+ auto& column = column_block[cid];
+ size_t rows_read = nrows;
+ RETURN_IF_ERROR(_column_iterators[cid]->next_batch(&rows_read, column));
+ DCHECK_EQ(nrows, rows_read);
+ }
+ return Status::OK();
+}
+
+void SegmentIterator::_init_current_block(vectorized::Block* block, std::vector<vectorized::MutableColumnPtr>& current_columns) {
+ bool is_block_mem_reuse= block->mem_reuse();
+ if (is_block_mem_reuse) {
+ size_t column_to_keep = _schema.num_column_ids();
+ for (int i = block->columns() - 1; i >= column_to_keep; i--) {
+ block->erase(i);
+ }
+ block->clear_column_data();
Review comment:
The column of block has be dealt in ```SegmentIterator::_init_current_block```.
So here block should only contain return columns.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] zuochunwei commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
zuochunwei commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r782796624
##########
File path: be/src/olap/rowset/segment_v2/segment_iterator.cpp
##########
@@ -581,9 +586,358 @@ Status SegmentIterator::next_batch(RowBlockV2* block) {
return Status::OK();
}
+/* ---------------------- for vecterization implementation ---------------------- */
+
+// todo(wb) need a UT here
+void SegmentIterator::_vec_init_lazy_materialization() {
+ _is_pred_column.resize(_schema.columns().size(), false);
+
+ std::set<ColumnId> pred_column_ids; // including short_cir_pred_col_id_set and vec_pred_col_id_set
+ _is_all_column_basic_type = true;
+ bool is_predicate_column_exists = false;
+ bool is_non_predicate_column_exists = false;
+
+ if (!_col_predicates.empty()) {
+ is_predicate_column_exists = true;
+
+ std::set<ColumnId> short_cir_pred_col_id_set; // using set for distinct cid
+ std::set<ColumnId> vec_pred_col_id_set;
+
+ for (auto predicate : _col_predicates) {
+ auto cid = predicate->column_id();
+ FieldType type = _schema.column(cid)->type();
+ _is_pred_column[cid] = true;
+ pred_column_ids.insert(cid);
+
+ // for date type which can not be executed in a vectorized way, using short circuit execution
+ if (type == OLAP_FIELD_TYPE_VARCHAR || type == OLAP_FIELD_TYPE_CHAR || type == OLAP_FIELD_TYPE_DECIMAL
+ || type == OLAP_FIELD_TYPE_DATE || predicate->is_in_predicate()) {
+ short_cir_pred_col_id_set.insert(cid);
+ _short_cir_eval_predicate.push_back(predicate);
+ _is_all_column_basic_type = false;
+ } else {
+ vec_pred_col_id_set.insert(predicate->column_id());
+ if (_pre_eval_block_predicate == nullptr) {
+ _pre_eval_block_predicate = new AndBlockColumnPredicate();
+ }
+ reinterpret_cast<MutilColumnBlockPredicate*>(_pre_eval_block_predicate)->add_column_predicate(new SingleColumnBlockPredicate(predicate));
+ }
+ }
+
+ std::set<ColumnId> del_cond_id_set;
+ _opts.delete_condition_predicates.get()->get_all_column_ids(del_cond_id_set);
+ short_cir_pred_col_id_set.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+ pred_column_ids.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+
+ if (_schema.column_ids().size() > pred_column_ids.size()) {
+ for (auto cid : _schema.column_ids()) {
+ if (!_is_pred_column[cid]) {
+ _non_predicate_columns.push_back(cid);
+ is_non_predicate_column_exists = true;
+ }
+ }
+ }
+
+ _vec_pred_column_ids.assign(vec_pred_col_id_set.cbegin(), vec_pred_col_id_set.cend());
+ _short_cir_pred_column_ids.assign(short_cir_pred_col_id_set.cbegin(), short_cir_pred_col_id_set.cend());
+ } else {
+ _is_all_column_basic_type = false;
+ is_non_predicate_column_exists = true;
+ for (auto cid : _schema.column_ids()) {
+ _non_predicate_columns.push_back(cid);
+ }
+ }
+
+ // note(wb) in following cases we disable lazy materialization
+ // case 1: when all column is basic type(is_all_column_basic_type = true)
+ // because we think `seek and read` cost > read page cost, lazy materialize may cause more `seek and read`, so disable it
+ // case 2: all column is predicate column
+ // case 3: all column is not predicate column
+ // todo(wb) need further research more lazy materialization rule, such as get more info from `statistics` for better decision
+ if (_is_all_column_basic_type) {
+ std::set<ColumnId> pred_set(_vec_pred_column_ids.begin(), _vec_pred_column_ids.end());
+ std::set<ColumnId> non_pred_set(_non_predicate_columns.begin(), _non_predicate_columns.end());
+
+ // when _is_all_column_basic_type = true, _first_read_column_ids should keep the same order with _schema.column_ids which stands for return column order
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (pred_set.find(cid) != pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ } else if (non_pred_set.find(cid) != non_pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ _is_pred_column[cid] = true; // in this case, non-predicate column should also be filtered by sel idx, so we regard it as pred columns
+ }
+ }
+
+ } else if (is_predicate_column_exists && !is_non_predicate_column_exists) {
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ } else if (!is_predicate_column_exists && is_non_predicate_column_exists) {
+ for (auto cid : _non_predicate_columns) {
+ _first_read_column_ids.push_back(cid);
+ }
+ } else {
+ _lazy_materialization_read = true;
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ }
+
+ // make _schema_block_id_map
+ _schema_block_id_map.resize(_schema.columns().size());
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ _schema_block_id_map[cid] = i;
+ }
+
+}
+
+Status SegmentIterator::_read_columns(const std::vector<ColumnId>& column_ids, vectorized::MutableColumns& column_block, size_t nrows) {
+ for (auto cid : column_ids) {
+ auto& column = column_block[cid];
+ size_t rows_read = nrows;
+ RETURN_IF_ERROR(_column_iterators[cid]->next_batch(&rows_read, column));
+ DCHECK_EQ(nrows, rows_read);
+ }
+ return Status::OK();
+}
+
+void SegmentIterator::_init_current_block(vectorized::Block* block, std::vector<vectorized::MutableColumnPtr>& current_columns) {
+ bool is_block_mem_reuse= block->mem_reuse();
+ if (is_block_mem_reuse) {
+ size_t column_to_keep = _schema.num_column_ids();
+ for (int i = block->columns() - 1; i >= column_to_keep; i--) {
+ block->erase(i);
+ }
+ block->clear_column_data();
+ } else { // pre fill output block here
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ auto* column_desc = _schema.columns()[cid];
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ if (column_desc->is_nullable()) {
+ block->insert({nullptr, std::make_shared<vectorized::DataTypeNullable>(std::move(data_type)), column_desc->name()});
+ } else {
+ block->insert({nullptr, std::move(data_type), column_desc->name()});
+ }
+ }
+ }
+
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (_is_pred_column[cid]) { //todo(wb) maybe we can relase it after output block
+ current_columns[cid]->clear();
+ } else { // non-predicate column
+ auto &column_desc = _schema.columns()[cid];
+ if (is_block_mem_reuse) {
+ current_columns[cid] = std::move(*block->get_by_position(i).column).mutate();
+ } else {
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ if (column_desc->is_nullable()) {
+ current_columns[cid] = doris::vectorized::ColumnNullable::create(
+ std::move(data_type->create_column()), doris::vectorized::ColumnUInt8::create());
+ } else {
+ current_columns[cid] = data_type->create_column();
+ }
+ }
+ if (column_desc->type() == OLAP_FIELD_TYPE_DATE) {
+ current_columns[cid]->set_date_type();
+ } else if (column_desc->type() == OLAP_FIELD_TYPE_DATETIME) {
+ current_columns[cid]->set_datetime_type();
+ }
+ }
+ }
+}
+
+void SegmentIterator::_output_non_pred_columns(vectorized::Block* block, bool is_block_mem_reuse) {
+ for (auto cid : _non_predicate_columns) {
+ block->replace_by_position(_schema_block_id_map[cid], std::move(_current_return_columns[cid]));
+ }
+ }
+
+void SegmentIterator::_output_column_by_sel_idx(vectorized::Block* block, std::vector<ColumnId> columnIds,
+ uint16_t* sel_rowid_idx, uint16_t select_size, bool is_block_mem_reuse) {
+ for (auto cid : columnIds) {
+ auto &column_ptr = _current_return_columns[cid];
+ if (is_block_mem_reuse) {
+ column_ptr->filter_by_selector(sel_rowid_idx, select_size,
+ &block->get_by_position(_schema_block_id_map[cid]).column);
+ } else {
+ block->replace_by_position(_schema_block_id_map[cid],
+ (*column_ptr).get_ptr()->filter_by_selector(sel_rowid_idx, select_size));
+ }
+ }
+ }
+
+
+Status SegmentIterator::_read_columns_by_index(uint32_t nrows_read_limit, uint32_t& nrows_read, bool set_block_rowid) {
+ do {
+ uint32_t range_from;
+ uint32_t range_to;
+ bool has_next_range =
+ _range_iter->next_range(nrows_read_limit - nrows_read, &range_from, &range_to);
+ if (!has_next_range) {
+ break;
+ }
+ if (_cur_rowid == 0 || _cur_rowid != range_from) {
+ _cur_rowid = range_from;
+ RETURN_IF_ERROR(_seek_columns(_first_read_column_ids, _cur_rowid));
+ }
+ size_t rows_to_read = range_to - range_from;
+ RETURN_IF_ERROR(_read_columns(_first_read_column_ids, _current_return_columns, rows_to_read));
+ _cur_rowid += rows_to_read;
+ if (set_block_rowid) {
+ for (uint32_t rid = range_from; rid < range_to; rid++) {
+ _block_rowids[nrows_read++] = rid;
+ }
+ } else {
+ nrows_read += rows_to_read;
+ }
+ } while (nrows_read < nrows_read_limit);
+ return Status::OK();
+}
+
+void SegmentIterator::_evaluate_vectorization_predicate(uint16_t* sel_rowid_idx, uint16_t& selected_size) {
+ uint16_t new_size = 0;
+ if (_vec_pred_column_ids.size() == 0) {
+ for (uint32_t i = 0; i < selected_size; ++i) {
+ sel_rowid_idx[new_size++] = i;
+ }
+ return;
+ }
+
+ uint16_t original_size = selected_size;
+ bool ret_flags[selected_size];
+ memset(ret_flags, 1, selected_size);
+ _pre_eval_block_predicate->evaluate_vec(_current_return_columns, selected_size, ret_flags);
+
+ for (uint32_t i = 0; i < selected_size; ++i) {
+ if (ret_flags[i]) {
+ sel_rowid_idx[new_size++] = i;
+ }
+ }
+
+ _opts.stats->rows_vec_cond_filtered += original_size - new_size;
+ selected_size = new_size;
+}
+
+void SegmentIterator::_evaluate_short_circuit_predicate(uint16_t* vec_sel_rowid_idx, uint16_t* selected_size_ptr) {
+ if (_short_cir_pred_column_ids.size() == 0) {
+ return;
+ }
+
+ for (auto column_predicate : _short_cir_eval_predicate) {
+ auto column_id = column_predicate->column_id();
+ auto& short_cir_column = _current_return_columns[column_id];
+ column_predicate->evaluate(*short_cir_column, vec_sel_rowid_idx, selected_size_ptr);
+ }
+
+ // evaluate delete condition
+ _opts.delete_condition_predicates->evaluate(_current_return_columns, vec_sel_rowid_idx, selected_size_ptr);
+}
+
+void SegmentIterator::_read_columns_by_rowids(std::vector<ColumnId>& read_column_ids, std::vector<rowid_t>& rowid_vector,
+ uint16_t* sel_rowid_idx, size_t select_size, vectorized::MutableColumns* mutable_columns) {
+ size_t start_idx = 0;
+ while (start_idx < select_size) {
+ size_t end_idx = start_idx + 1;
+ while (end_idx < select_size && (rowid_vector[sel_rowid_idx[end_idx - 1]] == rowid_vector[sel_rowid_idx[end_idx]] - 1)) {
+ end_idx++;
+ }
+ size_t range = end_idx - start_idx;
+ _seek_columns(read_column_ids, rowid_vector[sel_rowid_idx[start_idx]]);
+ _read_columns(read_column_ids, *mutable_columns, range);
+ start_idx += range;
+ }
+}
+
Status SegmentIterator::next_batch(vectorized::Block* block) {
- //TODO
- return Status::NotSupported("not implement now");
+ bool is_mem_reuse = block->mem_reuse();
+ SCOPED_RAW_TIMER(&_opts.stats->block_load_ns);
+ if (UNLIKELY(!_inited)) {
+ RETURN_IF_ERROR(_init(true));
Review comment:
i know your meaning, i am talking from the reasonableness
too many usages in doris, but i still think should separate these two functions
i modified this similar usage in BlockReader
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] zuochunwei commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
zuochunwei commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r782796624
##########
File path: be/src/olap/rowset/segment_v2/segment_iterator.cpp
##########
@@ -581,9 +586,358 @@ Status SegmentIterator::next_batch(RowBlockV2* block) {
return Status::OK();
}
+/* ---------------------- for vecterization implementation ---------------------- */
+
+// todo(wb) need a UT here
+void SegmentIterator::_vec_init_lazy_materialization() {
+ _is_pred_column.resize(_schema.columns().size(), false);
+
+ std::set<ColumnId> pred_column_ids; // including short_cir_pred_col_id_set and vec_pred_col_id_set
+ _is_all_column_basic_type = true;
+ bool is_predicate_column_exists = false;
+ bool is_non_predicate_column_exists = false;
+
+ if (!_col_predicates.empty()) {
+ is_predicate_column_exists = true;
+
+ std::set<ColumnId> short_cir_pred_col_id_set; // using set for distinct cid
+ std::set<ColumnId> vec_pred_col_id_set;
+
+ for (auto predicate : _col_predicates) {
+ auto cid = predicate->column_id();
+ FieldType type = _schema.column(cid)->type();
+ _is_pred_column[cid] = true;
+ pred_column_ids.insert(cid);
+
+ // for date type which can not be executed in a vectorized way, using short circuit execution
+ if (type == OLAP_FIELD_TYPE_VARCHAR || type == OLAP_FIELD_TYPE_CHAR || type == OLAP_FIELD_TYPE_DECIMAL
+ || type == OLAP_FIELD_TYPE_DATE || predicate->is_in_predicate()) {
+ short_cir_pred_col_id_set.insert(cid);
+ _short_cir_eval_predicate.push_back(predicate);
+ _is_all_column_basic_type = false;
+ } else {
+ vec_pred_col_id_set.insert(predicate->column_id());
+ if (_pre_eval_block_predicate == nullptr) {
+ _pre_eval_block_predicate = new AndBlockColumnPredicate();
+ }
+ reinterpret_cast<MutilColumnBlockPredicate*>(_pre_eval_block_predicate)->add_column_predicate(new SingleColumnBlockPredicate(predicate));
+ }
+ }
+
+ std::set<ColumnId> del_cond_id_set;
+ _opts.delete_condition_predicates.get()->get_all_column_ids(del_cond_id_set);
+ short_cir_pred_col_id_set.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+ pred_column_ids.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+
+ if (_schema.column_ids().size() > pred_column_ids.size()) {
+ for (auto cid : _schema.column_ids()) {
+ if (!_is_pred_column[cid]) {
+ _non_predicate_columns.push_back(cid);
+ is_non_predicate_column_exists = true;
+ }
+ }
+ }
+
+ _vec_pred_column_ids.assign(vec_pred_col_id_set.cbegin(), vec_pred_col_id_set.cend());
+ _short_cir_pred_column_ids.assign(short_cir_pred_col_id_set.cbegin(), short_cir_pred_col_id_set.cend());
+ } else {
+ _is_all_column_basic_type = false;
+ is_non_predicate_column_exists = true;
+ for (auto cid : _schema.column_ids()) {
+ _non_predicate_columns.push_back(cid);
+ }
+ }
+
+ // note(wb) in following cases we disable lazy materialization
+ // case 1: when all column is basic type(is_all_column_basic_type = true)
+ // because we think `seek and read` cost > read page cost, lazy materialize may cause more `seek and read`, so disable it
+ // case 2: all column is predicate column
+ // case 3: all column is not predicate column
+ // todo(wb) need further research more lazy materialization rule, such as get more info from `statistics` for better decision
+ if (_is_all_column_basic_type) {
+ std::set<ColumnId> pred_set(_vec_pred_column_ids.begin(), _vec_pred_column_ids.end());
+ std::set<ColumnId> non_pred_set(_non_predicate_columns.begin(), _non_predicate_columns.end());
+
+ // when _is_all_column_basic_type = true, _first_read_column_ids should keep the same order with _schema.column_ids which stands for return column order
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (pred_set.find(cid) != pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ } else if (non_pred_set.find(cid) != non_pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ _is_pred_column[cid] = true; // in this case, non-predicate column should also be filtered by sel idx, so we regard it as pred columns
+ }
+ }
+
+ } else if (is_predicate_column_exists && !is_non_predicate_column_exists) {
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ } else if (!is_predicate_column_exists && is_non_predicate_column_exists) {
+ for (auto cid : _non_predicate_columns) {
+ _first_read_column_ids.push_back(cid);
+ }
+ } else {
+ _lazy_materialization_read = true;
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ }
+
+ // make _schema_block_id_map
+ _schema_block_id_map.resize(_schema.columns().size());
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ _schema_block_id_map[cid] = i;
+ }
+
+}
+
+Status SegmentIterator::_read_columns(const std::vector<ColumnId>& column_ids, vectorized::MutableColumns& column_block, size_t nrows) {
+ for (auto cid : column_ids) {
+ auto& column = column_block[cid];
+ size_t rows_read = nrows;
+ RETURN_IF_ERROR(_column_iterators[cid]->next_batch(&rows_read, column));
+ DCHECK_EQ(nrows, rows_read);
+ }
+ return Status::OK();
+}
+
+void SegmentIterator::_init_current_block(vectorized::Block* block, std::vector<vectorized::MutableColumnPtr>& current_columns) {
+ bool is_block_mem_reuse= block->mem_reuse();
+ if (is_block_mem_reuse) {
+ size_t column_to_keep = _schema.num_column_ids();
+ for (int i = block->columns() - 1; i >= column_to_keep; i--) {
+ block->erase(i);
+ }
+ block->clear_column_data();
+ } else { // pre fill output block here
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ auto* column_desc = _schema.columns()[cid];
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ if (column_desc->is_nullable()) {
+ block->insert({nullptr, std::make_shared<vectorized::DataTypeNullable>(std::move(data_type)), column_desc->name()});
+ } else {
+ block->insert({nullptr, std::move(data_type), column_desc->name()});
+ }
+ }
+ }
+
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (_is_pred_column[cid]) { //todo(wb) maybe we can relase it after output block
+ current_columns[cid]->clear();
+ } else { // non-predicate column
+ auto &column_desc = _schema.columns()[cid];
+ if (is_block_mem_reuse) {
+ current_columns[cid] = std::move(*block->get_by_position(i).column).mutate();
+ } else {
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ if (column_desc->is_nullable()) {
+ current_columns[cid] = doris::vectorized::ColumnNullable::create(
+ std::move(data_type->create_column()), doris::vectorized::ColumnUInt8::create());
+ } else {
+ current_columns[cid] = data_type->create_column();
+ }
+ }
+ if (column_desc->type() == OLAP_FIELD_TYPE_DATE) {
+ current_columns[cid]->set_date_type();
+ } else if (column_desc->type() == OLAP_FIELD_TYPE_DATETIME) {
+ current_columns[cid]->set_datetime_type();
+ }
+ }
+ }
+}
+
+void SegmentIterator::_output_non_pred_columns(vectorized::Block* block, bool is_block_mem_reuse) {
+ for (auto cid : _non_predicate_columns) {
+ block->replace_by_position(_schema_block_id_map[cid], std::move(_current_return_columns[cid]));
+ }
+ }
+
+void SegmentIterator::_output_column_by_sel_idx(vectorized::Block* block, std::vector<ColumnId> columnIds,
+ uint16_t* sel_rowid_idx, uint16_t select_size, bool is_block_mem_reuse) {
+ for (auto cid : columnIds) {
+ auto &column_ptr = _current_return_columns[cid];
+ if (is_block_mem_reuse) {
+ column_ptr->filter_by_selector(sel_rowid_idx, select_size,
+ &block->get_by_position(_schema_block_id_map[cid]).column);
+ } else {
+ block->replace_by_position(_schema_block_id_map[cid],
+ (*column_ptr).get_ptr()->filter_by_selector(sel_rowid_idx, select_size));
+ }
+ }
+ }
+
+
+Status SegmentIterator::_read_columns_by_index(uint32_t nrows_read_limit, uint32_t& nrows_read, bool set_block_rowid) {
+ do {
+ uint32_t range_from;
+ uint32_t range_to;
+ bool has_next_range =
+ _range_iter->next_range(nrows_read_limit - nrows_read, &range_from, &range_to);
+ if (!has_next_range) {
+ break;
+ }
+ if (_cur_rowid == 0 || _cur_rowid != range_from) {
+ _cur_rowid = range_from;
+ RETURN_IF_ERROR(_seek_columns(_first_read_column_ids, _cur_rowid));
+ }
+ size_t rows_to_read = range_to - range_from;
+ RETURN_IF_ERROR(_read_columns(_first_read_column_ids, _current_return_columns, rows_to_read));
+ _cur_rowid += rows_to_read;
+ if (set_block_rowid) {
+ for (uint32_t rid = range_from; rid < range_to; rid++) {
+ _block_rowids[nrows_read++] = rid;
+ }
+ } else {
+ nrows_read += rows_to_read;
+ }
+ } while (nrows_read < nrows_read_limit);
+ return Status::OK();
+}
+
+void SegmentIterator::_evaluate_vectorization_predicate(uint16_t* sel_rowid_idx, uint16_t& selected_size) {
+ uint16_t new_size = 0;
+ if (_vec_pred_column_ids.size() == 0) {
+ for (uint32_t i = 0; i < selected_size; ++i) {
+ sel_rowid_idx[new_size++] = i;
+ }
+ return;
+ }
+
+ uint16_t original_size = selected_size;
+ bool ret_flags[selected_size];
+ memset(ret_flags, 1, selected_size);
+ _pre_eval_block_predicate->evaluate_vec(_current_return_columns, selected_size, ret_flags);
+
+ for (uint32_t i = 0; i < selected_size; ++i) {
+ if (ret_flags[i]) {
+ sel_rowid_idx[new_size++] = i;
+ }
+ }
+
+ _opts.stats->rows_vec_cond_filtered += original_size - new_size;
+ selected_size = new_size;
+}
+
+void SegmentIterator::_evaluate_short_circuit_predicate(uint16_t* vec_sel_rowid_idx, uint16_t* selected_size_ptr) {
+ if (_short_cir_pred_column_ids.size() == 0) {
+ return;
+ }
+
+ for (auto column_predicate : _short_cir_eval_predicate) {
+ auto column_id = column_predicate->column_id();
+ auto& short_cir_column = _current_return_columns[column_id];
+ column_predicate->evaluate(*short_cir_column, vec_sel_rowid_idx, selected_size_ptr);
+ }
+
+ // evaluate delete condition
+ _opts.delete_condition_predicates->evaluate(_current_return_columns, vec_sel_rowid_idx, selected_size_ptr);
+}
+
+void SegmentIterator::_read_columns_by_rowids(std::vector<ColumnId>& read_column_ids, std::vector<rowid_t>& rowid_vector,
+ uint16_t* sel_rowid_idx, size_t select_size, vectorized::MutableColumns* mutable_columns) {
+ size_t start_idx = 0;
+ while (start_idx < select_size) {
+ size_t end_idx = start_idx + 1;
+ while (end_idx < select_size && (rowid_vector[sel_rowid_idx[end_idx - 1]] == rowid_vector[sel_rowid_idx[end_idx]] - 1)) {
+ end_idx++;
+ }
+ size_t range = end_idx - start_idx;
+ _seek_columns(read_column_ids, rowid_vector[sel_rowid_idx[start_idx]]);
+ _read_columns(read_column_ids, *mutable_columns, range);
+ start_idx += range;
+ }
+}
+
Status SegmentIterator::next_batch(vectorized::Block* block) {
- //TODO
- return Status::NotSupported("not implement now");
+ bool is_mem_reuse = block->mem_reuse();
+ SCOPED_RAW_TIMER(&_opts.stats->block_load_ns);
+ if (UNLIKELY(!_inited)) {
+ RETURN_IF_ERROR(_init(true));
Review comment:
i know your meaning, i am talking from the reasonableness
too many usages in doris, but i still think should separate these two functions
i modified this usage in BlockReader
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] zuochunwei commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
zuochunwei commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r782798142
##########
File path: be/src/olap/rowset/segment_v2/segment_iterator.cpp
##########
@@ -581,9 +586,358 @@ Status SegmentIterator::next_batch(RowBlockV2* block) {
return Status::OK();
}
+/* ---------------------- for vecterization implementation ---------------------- */
+
+// todo(wb) need a UT here
+void SegmentIterator::_vec_init_lazy_materialization() {
+ _is_pred_column.resize(_schema.columns().size(), false);
+
+ std::set<ColumnId> pred_column_ids; // including short_cir_pred_col_id_set and vec_pred_col_id_set
+ _is_all_column_basic_type = true;
+ bool is_predicate_column_exists = false;
+ bool is_non_predicate_column_exists = false;
+
+ if (!_col_predicates.empty()) {
+ is_predicate_column_exists = true;
+
+ std::set<ColumnId> short_cir_pred_col_id_set; // using set for distinct cid
+ std::set<ColumnId> vec_pred_col_id_set;
+
+ for (auto predicate : _col_predicates) {
+ auto cid = predicate->column_id();
+ FieldType type = _schema.column(cid)->type();
+ _is_pred_column[cid] = true;
+ pred_column_ids.insert(cid);
+
+ // for date type which can not be executed in a vectorized way, using short circuit execution
+ if (type == OLAP_FIELD_TYPE_VARCHAR || type == OLAP_FIELD_TYPE_CHAR || type == OLAP_FIELD_TYPE_DECIMAL
+ || type == OLAP_FIELD_TYPE_DATE || predicate->is_in_predicate()) {
+ short_cir_pred_col_id_set.insert(cid);
+ _short_cir_eval_predicate.push_back(predicate);
+ _is_all_column_basic_type = false;
+ } else {
+ vec_pred_col_id_set.insert(predicate->column_id());
+ if (_pre_eval_block_predicate == nullptr) {
+ _pre_eval_block_predicate = new AndBlockColumnPredicate();
+ }
+ reinterpret_cast<MutilColumnBlockPredicate*>(_pre_eval_block_predicate)->add_column_predicate(new SingleColumnBlockPredicate(predicate));
+ }
+ }
+
+ std::set<ColumnId> del_cond_id_set;
+ _opts.delete_condition_predicates.get()->get_all_column_ids(del_cond_id_set);
+ short_cir_pred_col_id_set.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+ pred_column_ids.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+
+ if (_schema.column_ids().size() > pred_column_ids.size()) {
+ for (auto cid : _schema.column_ids()) {
+ if (!_is_pred_column[cid]) {
+ _non_predicate_columns.push_back(cid);
+ is_non_predicate_column_exists = true;
+ }
+ }
+ }
+
+ _vec_pred_column_ids.assign(vec_pred_col_id_set.cbegin(), vec_pred_col_id_set.cend());
+ _short_cir_pred_column_ids.assign(short_cir_pred_col_id_set.cbegin(), short_cir_pred_col_id_set.cend());
+ } else {
+ _is_all_column_basic_type = false;
+ is_non_predicate_column_exists = true;
+ for (auto cid : _schema.column_ids()) {
+ _non_predicate_columns.push_back(cid);
+ }
+ }
+
+ // note(wb) in following cases we disable lazy materialization
+ // case 1: when all column is basic type(is_all_column_basic_type = true)
+ // because we think `seek and read` cost > read page cost, lazy materialize may cause more `seek and read`, so disable it
+ // case 2: all column is predicate column
+ // case 3: all column is not predicate column
+ // todo(wb) need further research more lazy materialization rule, such as get more info from `statistics` for better decision
+ if (_is_all_column_basic_type) {
+ std::set<ColumnId> pred_set(_vec_pred_column_ids.begin(), _vec_pred_column_ids.end());
+ std::set<ColumnId> non_pred_set(_non_predicate_columns.begin(), _non_predicate_columns.end());
+
+ // when _is_all_column_basic_type = true, _first_read_column_ids should keep the same order with _schema.column_ids which stands for return column order
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (pred_set.find(cid) != pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ } else if (non_pred_set.find(cid) != non_pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ _is_pred_column[cid] = true; // in this case, non-predicate column should also be filtered by sel idx, so we regard it as pred columns
+ }
+ }
+
+ } else if (is_predicate_column_exists && !is_non_predicate_column_exists) {
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ } else if (!is_predicate_column_exists && is_non_predicate_column_exists) {
+ for (auto cid : _non_predicate_columns) {
+ _first_read_column_ids.push_back(cid);
+ }
+ } else {
+ _lazy_materialization_read = true;
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ }
+
+ // make _schema_block_id_map
+ _schema_block_id_map.resize(_schema.columns().size());
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ _schema_block_id_map[cid] = i;
+ }
+
+}
+
+Status SegmentIterator::_read_columns(const std::vector<ColumnId>& column_ids, vectorized::MutableColumns& column_block, size_t nrows) {
+ for (auto cid : column_ids) {
+ auto& column = column_block[cid];
+ size_t rows_read = nrows;
+ RETURN_IF_ERROR(_column_iterators[cid]->next_batch(&rows_read, column));
+ DCHECK_EQ(nrows, rows_read);
+ }
+ return Status::OK();
+}
+
+void SegmentIterator::_init_current_block(vectorized::Block* block, std::vector<vectorized::MutableColumnPtr>& current_columns) {
+ bool is_block_mem_reuse= block->mem_reuse();
+ if (is_block_mem_reuse) {
+ size_t column_to_keep = _schema.num_column_ids();
+ for (int i = block->columns() - 1; i >= column_to_keep; i--) {
+ block->erase(i);
+ }
+ block->clear_column_data();
Review comment:
check clear_column_data(with arg) 's implement, i think it provided what you want
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] wangbo commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
wangbo commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781762132
##########
File path: be/src/olap/rowset/segment_v2/binary_dict_page.cpp
##########
@@ -257,23 +257,33 @@ Status BinaryDictPageDecoder::next_batch(size_t* n, vectorized::MutableColumnPtr
const int32_t* data_array = reinterpret_cast<const int32_t*>(_bit_shuffle_ptr->_chunk.data);
size_t start_index = _bit_shuffle_ptr->_cur_index;
- // todo(wb) support nullable
- if (dst->is_predicate_column()) {
+ auto* dst_col_ptr = dst.get();
+ if (dst->is_nullable()) {
+ auto nullable_column = assert_cast<vectorized::ColumnNullable*>(dst.get());
+ dst_col_ptr = nullable_column->get_nested_column_ptr().get();
+
+ // fill null bitmap here, not null;
+ for (int i = 0; i < max_fetch; i++) {
+ nullable_column->get_null_map_data().push_back(0);
+ }
+ }
+
+ if (dst_col_ptr->is_predicate_column()) {
Review comment:
Because current class is ```binary_dict_page```, only ```ColumnStringValue``` will enter this method.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] zuochunwei commented on pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
zuochunwei commented on pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#issuecomment-1009743144
i need spend more time to check this PR carefully, so give me more time, i will compete in a few days!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org
[GitHub] [incubator-doris] zuochunwei commented on a change in pull request #7613: [Vectorization] support SegmentIterator vectorization
Posted by GitBox <gi...@apache.org>.
zuochunwei commented on a change in pull request #7613:
URL: https://github.com/apache/incubator-doris/pull/7613#discussion_r781958858
##########
File path: be/src/olap/rowset/segment_v2/segment_iterator.cpp
##########
@@ -581,9 +586,358 @@ Status SegmentIterator::next_batch(RowBlockV2* block) {
return Status::OK();
}
+/* ---------------------- for vecterization implementation ---------------------- */
+
+// todo(wb) need a UT here
+void SegmentIterator::_vec_init_lazy_materialization() {
+ _is_pred_column.resize(_schema.columns().size(), false);
+
+ std::set<ColumnId> pred_column_ids; // including short_cir_pred_col_id_set and vec_pred_col_id_set
+ _is_all_column_basic_type = true;
+ bool is_predicate_column_exists = false;
+ bool is_non_predicate_column_exists = false;
+
+ if (!_col_predicates.empty()) {
+ is_predicate_column_exists = true;
+
+ std::set<ColumnId> short_cir_pred_col_id_set; // using set for distinct cid
+ std::set<ColumnId> vec_pred_col_id_set;
+
+ for (auto predicate : _col_predicates) {
+ auto cid = predicate->column_id();
+ FieldType type = _schema.column(cid)->type();
+ _is_pred_column[cid] = true;
+ pred_column_ids.insert(cid);
+
+ // for date type which can not be executed in a vectorized way, using short circuit execution
+ if (type == OLAP_FIELD_TYPE_VARCHAR || type == OLAP_FIELD_TYPE_CHAR || type == OLAP_FIELD_TYPE_DECIMAL
+ || type == OLAP_FIELD_TYPE_DATE || predicate->is_in_predicate()) {
+ short_cir_pred_col_id_set.insert(cid);
+ _short_cir_eval_predicate.push_back(predicate);
+ _is_all_column_basic_type = false;
+ } else {
+ vec_pred_col_id_set.insert(predicate->column_id());
+ if (_pre_eval_block_predicate == nullptr) {
+ _pre_eval_block_predicate = new AndBlockColumnPredicate();
+ }
+ reinterpret_cast<MutilColumnBlockPredicate*>(_pre_eval_block_predicate)->add_column_predicate(new SingleColumnBlockPredicate(predicate));
+ }
+ }
+
+ std::set<ColumnId> del_cond_id_set;
+ _opts.delete_condition_predicates.get()->get_all_column_ids(del_cond_id_set);
+ short_cir_pred_col_id_set.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+ pred_column_ids.insert(del_cond_id_set.begin(), del_cond_id_set.end());
+
+ if (_schema.column_ids().size() > pred_column_ids.size()) {
+ for (auto cid : _schema.column_ids()) {
+ if (!_is_pred_column[cid]) {
+ _non_predicate_columns.push_back(cid);
+ is_non_predicate_column_exists = true;
+ }
+ }
+ }
+
+ _vec_pred_column_ids.assign(vec_pred_col_id_set.cbegin(), vec_pred_col_id_set.cend());
+ _short_cir_pred_column_ids.assign(short_cir_pred_col_id_set.cbegin(), short_cir_pred_col_id_set.cend());
+ } else {
+ _is_all_column_basic_type = false;
+ is_non_predicate_column_exists = true;
+ for (auto cid : _schema.column_ids()) {
+ _non_predicate_columns.push_back(cid);
+ }
+ }
+
+ // note(wb) in following cases we disable lazy materialization
+ // case 1: when all column is basic type(is_all_column_basic_type = true)
+ // because we think `seek and read` cost > read page cost, lazy materialize may cause more `seek and read`, so disable it
+ // case 2: all column is predicate column
+ // case 3: all column is not predicate column
+ // todo(wb) need further research more lazy materialization rule, such as get more info from `statistics` for better decision
+ if (_is_all_column_basic_type) {
+ std::set<ColumnId> pred_set(_vec_pred_column_ids.begin(), _vec_pred_column_ids.end());
+ std::set<ColumnId> non_pred_set(_non_predicate_columns.begin(), _non_predicate_columns.end());
+
+ // when _is_all_column_basic_type = true, _first_read_column_ids should keep the same order with _schema.column_ids which stands for return column order
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (pred_set.find(cid) != pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ } else if (non_pred_set.find(cid) != non_pred_set.end()) {
+ _first_read_column_ids.push_back(cid);
+ _is_pred_column[cid] = true; // in this case, non-predicate column should also be filtered by sel idx, so we regard it as pred columns
+ }
+ }
+
+ } else if (is_predicate_column_exists && !is_non_predicate_column_exists) {
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ } else if (!is_predicate_column_exists && is_non_predicate_column_exists) {
+ for (auto cid : _non_predicate_columns) {
+ _first_read_column_ids.push_back(cid);
+ }
+ } else {
+ _lazy_materialization_read = true;
+ _first_read_column_ids.assign(pred_column_ids.cbegin(), pred_column_ids.cend());
+ }
+
+ // make _schema_block_id_map
+ _schema_block_id_map.resize(_schema.columns().size());
+ for (int i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ _schema_block_id_map[cid] = i;
+ }
+
+}
+
+Status SegmentIterator::_read_columns(const std::vector<ColumnId>& column_ids, vectorized::MutableColumns& column_block, size_t nrows) {
+ for (auto cid : column_ids) {
+ auto& column = column_block[cid];
+ size_t rows_read = nrows;
+ RETURN_IF_ERROR(_column_iterators[cid]->next_batch(&rows_read, column));
+ DCHECK_EQ(nrows, rows_read);
+ }
+ return Status::OK();
+}
+
+void SegmentIterator::_init_current_block(vectorized::Block* block, std::vector<vectorized::MutableColumnPtr>& current_columns) {
+ bool is_block_mem_reuse= block->mem_reuse();
+ if (is_block_mem_reuse) {
+ size_t column_to_keep = _schema.num_column_ids();
+ for (int i = block->columns() - 1; i >= column_to_keep; i--) {
+ block->erase(i);
+ }
+ block->clear_column_data();
+ } else { // pre fill output block here
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ auto* column_desc = _schema.columns()[cid];
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ if (column_desc->is_nullable()) {
+ block->insert({nullptr, std::make_shared<vectorized::DataTypeNullable>(std::move(data_type)), column_desc->name()});
+ } else {
+ block->insert({nullptr, std::move(data_type), column_desc->name()});
+ }
+ }
+ }
+
+ for (size_t i = 0; i < _schema.num_column_ids(); i++) {
+ auto cid = _schema.column_ids()[i];
+ if (_is_pred_column[cid]) { //todo(wb) maybe we can relase it after output block
+ current_columns[cid]->clear();
+ } else { // non-predicate column
+ auto &column_desc = _schema.columns()[cid];
+ if (is_block_mem_reuse) {
+ current_columns[cid] = std::move(*block->get_by_position(i).column).mutate();
+ } else {
+ auto data_type = Schema::get_data_type_ptr(column_desc->type());
+ if (column_desc->is_nullable()) {
+ current_columns[cid] = doris::vectorized::ColumnNullable::create(
+ std::move(data_type->create_column()), doris::vectorized::ColumnUInt8::create());
+ } else {
+ current_columns[cid] = data_type->create_column();
+ }
+ }
+ if (column_desc->type() == OLAP_FIELD_TYPE_DATE) {
+ current_columns[cid]->set_date_type();
+ } else if (column_desc->type() == OLAP_FIELD_TYPE_DATETIME) {
+ current_columns[cid]->set_datetime_type();
+ }
+ }
+ }
+}
+
+void SegmentIterator::_output_non_pred_columns(vectorized::Block* block, bool is_block_mem_reuse) {
+ for (auto cid : _non_predicate_columns) {
+ block->replace_by_position(_schema_block_id_map[cid], std::move(_current_return_columns[cid]));
+ }
+ }
+
+void SegmentIterator::_output_column_by_sel_idx(vectorized::Block* block, std::vector<ColumnId> columnIds,
+ uint16_t* sel_rowid_idx, uint16_t select_size, bool is_block_mem_reuse) {
+ for (auto cid : columnIds) {
+ auto &column_ptr = _current_return_columns[cid];
+ if (is_block_mem_reuse) {
+ column_ptr->filter_by_selector(sel_rowid_idx, select_size,
+ &block->get_by_position(_schema_block_id_map[cid]).column);
+ } else {
+ block->replace_by_position(_schema_block_id_map[cid],
+ (*column_ptr).get_ptr()->filter_by_selector(sel_rowid_idx, select_size));
+ }
+ }
+ }
+
+
+Status SegmentIterator::_read_columns_by_index(uint32_t nrows_read_limit, uint32_t& nrows_read, bool set_block_rowid) {
+ do {
+ uint32_t range_from;
+ uint32_t range_to;
+ bool has_next_range =
+ _range_iter->next_range(nrows_read_limit - nrows_read, &range_from, &range_to);
+ if (!has_next_range) {
+ break;
+ }
+ if (_cur_rowid == 0 || _cur_rowid != range_from) {
+ _cur_rowid = range_from;
+ RETURN_IF_ERROR(_seek_columns(_first_read_column_ids, _cur_rowid));
+ }
+ size_t rows_to_read = range_to - range_from;
+ RETURN_IF_ERROR(_read_columns(_first_read_column_ids, _current_return_columns, rows_to_read));
+ _cur_rowid += rows_to_read;
+ if (set_block_rowid) {
+ for (uint32_t rid = range_from; rid < range_to; rid++) {
+ _block_rowids[nrows_read++] = rid;
+ }
+ } else {
+ nrows_read += rows_to_read;
+ }
+ } while (nrows_read < nrows_read_limit);
+ return Status::OK();
+}
+
+void SegmentIterator::_evaluate_vectorization_predicate(uint16_t* sel_rowid_idx, uint16_t& selected_size) {
+ uint16_t new_size = 0;
+ if (_vec_pred_column_ids.size() == 0) {
+ for (uint32_t i = 0; i < selected_size; ++i) {
+ sel_rowid_idx[new_size++] = i;
+ }
+ return;
+ }
+
+ uint16_t original_size = selected_size;
+ bool ret_flags[selected_size];
+ memset(ret_flags, 1, selected_size);
+ _pre_eval_block_predicate->evaluate_vec(_current_return_columns, selected_size, ret_flags);
+
+ for (uint32_t i = 0; i < selected_size; ++i) {
+ if (ret_flags[i]) {
+ sel_rowid_idx[new_size++] = i;
+ }
+ }
+
+ _opts.stats->rows_vec_cond_filtered += original_size - new_size;
+ selected_size = new_size;
+}
+
+void SegmentIterator::_evaluate_short_circuit_predicate(uint16_t* vec_sel_rowid_idx, uint16_t* selected_size_ptr) {
+ if (_short_cir_pred_column_ids.size() == 0) {
+ return;
+ }
+
+ for (auto column_predicate : _short_cir_eval_predicate) {
+ auto column_id = column_predicate->column_id();
+ auto& short_cir_column = _current_return_columns[column_id];
+ column_predicate->evaluate(*short_cir_column, vec_sel_rowid_idx, selected_size_ptr);
+ }
+
+ // evaluate delete condition
+ _opts.delete_condition_predicates->evaluate(_current_return_columns, vec_sel_rowid_idx, selected_size_ptr);
+}
+
+void SegmentIterator::_read_columns_by_rowids(std::vector<ColumnId>& read_column_ids, std::vector<rowid_t>& rowid_vector,
+ uint16_t* sel_rowid_idx, size_t select_size, vectorized::MutableColumns* mutable_columns) {
+ size_t start_idx = 0;
+ while (start_idx < select_size) {
+ size_t end_idx = start_idx + 1;
+ while (end_idx < select_size && (rowid_vector[sel_rowid_idx[end_idx - 1]] == rowid_vector[sel_rowid_idx[end_idx]] - 1)) {
+ end_idx++;
+ }
+ size_t range = end_idx - start_idx;
+ _seek_columns(read_column_ids, rowid_vector[sel_rowid_idx[start_idx]]);
+ _read_columns(read_column_ids, *mutable_columns, range);
+ start_idx += range;
+ }
+}
+
Status SegmentIterator::next_batch(vectorized::Block* block) {
- //TODO
- return Status::NotSupported("not implement now");
+ bool is_mem_reuse = block->mem_reuse();
+ SCOPED_RAW_TIMER(&_opts.stats->block_load_ns);
+ if (UNLIKELY(!_inited)) {
+ RETURN_IF_ERROR(_init(true));
Review comment:
condition init is not a good practice although this usage is frequent
separate init from next_batch because these two methods do absolutely different things
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org