From 2e64e7adcb96bfb523f19b8393272b48e22c0aa7 Mon Sep 17 00:00:00 2001 From: xianyu-w <707512433@qq.com> Date: Tue, 10 Dec 2024 16:15:39 +0000 Subject: [PATCH] Add hint index_asc/index_desc and Adjust scan direction at the end of the plan generation --- src/objit/include/objit/common/ob_item_type.h | 4 + src/sql/optimizer/ob_index_info_cache.h | 4 + src/sql/optimizer/ob_join_order.cpp | 19 ++++- src/sql/optimizer/ob_join_order.h | 3 + src/sql/optimizer/ob_log_plan.cpp | 6 +- src/sql/optimizer/ob_log_sort.cpp | 2 +- src/sql/optimizer/ob_log_sort.h | 7 +- src/sql/optimizer/ob_log_table_scan.cpp | 52 +++++++++++-- src/sql/optimizer/ob_log_table_scan.h | 1 + src/sql/optimizer/ob_logical_operator.cpp | 16 ++++ src/sql/optimizer/ob_optimizer.h | 1 + src/sql/parser/sql_parser_mysql_mode.l | 2 + src/sql/parser/sql_parser_mysql_mode.y | 10 ++- src/sql/resolver/dml/ob_dml_resolver.cpp | 10 ++- src/sql/resolver/dml/ob_hint.cpp | 5 +- src/sql/resolver/dml/ob_hint.h | 20 ++++- src/sql/resolver/dml/ob_sql_hint.cpp | 77 ++++++++++++++++++- src/sql/resolver/dml/ob_sql_hint.h | 4 + .../ob_transform_late_materialization.cpp | 6 ++ 19 files changed, 226 insertions(+), 23 deletions(-) diff --git a/src/objit/include/objit/common/ob_item_type.h b/src/objit/include/objit/common/ob_item_type.h index 1b5b38e2e..1f2eae997 100644 --- a/src/objit/include/objit/common/ob_item_type.h +++ b/src/objit/include/objit/common/ob_item_type.h @@ -2690,6 +2690,10 @@ typedef enum ObItemType T_CREATE_WRAPPED_FUNCTION = 4769, T_CREATE_WRAPPED_PROCEDURE = 4770, T_BASE64_CIPHER = 4771, + + // optimizer hint + T_INDEX_ASC_HINT = 4772, + T_INDEX_DESC_HINT = 4773, T_MAX //Attention: add a new type before T_MAX } ObItemType; diff --git a/src/sql/optimizer/ob_index_info_cache.h b/src/sql/optimizer/ob_index_info_cache.h index 0987a3cb9..14f4f2274 100644 --- a/src/sql/optimizer/ob_index_info_cache.h +++ b/src/sql/optimizer/ob_index_info_cache.h @@ -157,6 +157,7 @@ public: is_fulltext_index_(false), is_multivalue_index_(false), is_vector_index_(false), + force_direction_(false), range_info_(), ordering_info_(), interesting_order_info_(OrderingFlag::NOT_MATCH), @@ -200,6 +201,8 @@ public: ObShardingInfo *get_sharding_info() const { return sharding_info_; } bool is_multivalue_index() const { return is_multivalue_index_; } void set_is_multivalue_index(const bool is_multivalue_index) { is_multivalue_index_ = is_multivalue_index; } + bool is_force_direction() const { return force_direction_; } + void set_force_direction(bool force) { force_direction_ = force; } TO_STRING_KV(K_(index_id), K_(is_unique_index), K_(is_index_back), K_(is_index_global), K_(is_fulltext_index), K_(is_multivalue_index), K_(range_info), K_(ordering_info), K_(interesting_order_info), K_(interesting_order_prefix_count)); @@ -212,6 +215,7 @@ private: bool is_fulltext_index_; bool is_multivalue_index_; bool is_vector_index_; + bool force_direction_; QueryRangeInfo range_info_; OrderingInfo ordering_info_; int64_t interesting_order_info_; // 记录索引的序在stmt中的哪些地方用到 e.g. join, group by, order by diff --git a/src/sql/optimizer/ob_join_order.cpp b/src/sql/optimizer/ob_join_order.cpp index 5b2819f04..e00998765 100755 --- a/src/sql/optimizer/ob_join_order.cpp +++ b/src/sql/optimizer/ob_join_order.cpp @@ -1776,6 +1776,7 @@ int ObJoinOrder::create_one_access_path(const uint64_t table_id, ap->index_prefix_ = index_info_entry->get_range_info().get_index_prefix(); ap->use_column_store_ = use_column_store; ap->est_cost_info_.use_column_store_ = use_column_store; + ap->force_direction_ = index_info_entry->is_force_direction(); ap->contain_das_op_ = ap->use_das_; ap->is_ror_ = (ref_id == index_id) ? true @@ -2153,6 +2154,7 @@ int ObJoinOrder::get_access_path_ordering(const uint64_t table_id, common::ObIArray &index_keys, common::ObIArray &ordering, ObOrderDirection &direction, + bool &force_direction, const bool is_index_back) { int ret = OB_SUCCESS; @@ -2161,10 +2163,13 @@ int ObJoinOrder::get_access_path_ordering(const uint64_t table_id, ObOptimizerContext *opt_ctx = NULL; ObSqlSchemaGuard *schema_guard = NULL; const ObTableSchema *index_schema = NULL; + ObOrderDirection hint_direction = UNORDERED; + force_direction = false; if (OB_ISNULL(get_plan()) || OB_ISNULL(stmt = get_plan()->get_stmt()) || OB_ISNULL(opt_ctx = &get_plan()->get_optimizer_context()) - || OB_ISNULL(schema_guard = opt_ctx->get_sql_schema_guard())) { + || OB_ISNULL(schema_guard = opt_ctx->get_sql_schema_guard()) + || OB_ISNULL(opt_ctx->get_query_ctx())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("NULL pointer error", K(get_plan()), K(stmt), K(opt_ctx), K(schema_guard), K(ret)); @@ -2181,6 +2186,14 @@ int ObJoinOrder::get_access_path_ordering(const uint64_t table_id, // for global index lookup without keep order, the ordering is wrong. } else if (OB_FAIL(append(ordering, index_keys))) { LOG_WARN("failed to append index ordering expr", K(ret)); + } else if (OB_FAIL(get_plan()->get_log_plan_hint().check_scan_direction(*opt_ctx->get_query_ctx(), + table_id, + index_id, + hint_direction))) { + LOG_WARN("failed to check scan direction", K(ret), K(table_id)); + } else if (UNORDERED != hint_direction) { + direction = hint_direction; + force_direction = true; } else if (OB_FAIL(get_index_scan_direction(ordering, stmt, get_plan()->get_equal_sets(), direction))) { LOG_WARN("failed to get index scan direction", K(ret)); @@ -2639,6 +2652,7 @@ int ObJoinOrder::fill_index_info_entry(const uint64_t table_id, entry->set_index_id(index_id); int64_t interesting_order_info = OrderingFlag::NOT_MATCH; int64_t max_prefix_count = 0; + bool force_direction = false; if (OB_FAIL(get_simple_index_info(table_id, base_table_id, index_id, is_unique_index, is_index_back, is_index_global))) { LOG_WARN("failed to get simple index info", K(ret)); @@ -2646,6 +2660,7 @@ int ObJoinOrder::fill_index_info_entry(const uint64_t table_id, entry->get_ordering_info().get_index_keys(), entry->get_ordering_info().get_ordering(), direction, + force_direction, is_index_back))) { LOG_WARN("get access path ordering ", K(ret)); } else { @@ -2657,6 +2672,7 @@ int ObJoinOrder::fill_index_info_entry(const uint64_t table_id, entry->set_is_multivalue_index(index_schema->is_multivalue_index_aux()); entry->set_is_vector_index(index_schema->is_vec_index()); entry->get_ordering_info().set_scan_direction(direction); + entry->set_force_direction(force_direction); } if (OB_SUCC(ret)) { ObSEArray index_ordering; @@ -6194,6 +6210,7 @@ int AccessPath::assign(const AccessPath &other, common::ObIAllocator *allocator) table_partition_info_ = other.table_partition_info_; is_get_ = other.is_get_; order_direction_ = other.order_direction_; + force_direction_ = other.force_direction_; is_hash_index_ = other.is_hash_index_; sample_info_ = other.sample_info_; range_prefix_count_ = other.range_prefix_count_; diff --git a/src/sql/optimizer/ob_join_order.h b/src/sql/optimizer/ob_join_order.h index ccc3eb31b..19fde0d41 100755 --- a/src/sql/optimizer/ob_join_order.h +++ b/src/sql/optimizer/ob_join_order.h @@ -573,6 +573,7 @@ struct TRIndexAccessInfo pre_range_graph_(NULL), is_get_(false), order_direction_(direction), + force_direction_(false), is_hash_index_(false), est_cost_info_(table_id, ref_table_id, @@ -727,6 +728,7 @@ struct TRIndexAccessInfo ObPreRangeGraph* pre_range_graph_; // pre_query_graph for each access path bool is_get_; ObOrderDirection order_direction_;//序的方向(升序or倒序) + bool force_direction_; bool is_hash_index_; // is hash index (virtual table and is index) ObCostTableScanInfo est_cost_info_; // estimate cost info common::ObSEArray &index_keys, common::ObIArray &ordering, ObOrderDirection &direction, + bool &force_direction, const bool is_index_back); int get_index_scan_direction(const ObIArray &keys, diff --git a/src/sql/optimizer/ob_log_plan.cpp b/src/sql/optimizer/ob_log_plan.cpp index ea8c6844b..c0e8b2517 100644 --- a/src/sql/optimizer/ob_log_plan.cpp +++ b/src/sql/optimizer/ob_log_plan.cpp @@ -9468,6 +9468,9 @@ int ObLogPlan::plan_tree_traverse(const TraverseOp &operation, void *ctx) case ALLOC_STARTUP_EXPR: default: break; + case ADJUST_SCAN_DIRECTION: { + break; + } } if (OB_SUCC(ret)) { if (((PX_ESTIMATE_SIZE == operation) || @@ -10929,7 +10932,8 @@ int ObLogPlan::generate_plan() GEN_LOCATION_CONSTRAINT, PX_ESTIMATE_SIZE, ALLOC_STARTUP_EXPR, - COLLECT_BATCH_EXEC_PARAM))) { + COLLECT_BATCH_EXEC_PARAM, + ADJUST_SCAN_DIRECTION))) { LOG_WARN("failed to do plan traverse", K(ret)); } else if (OB_FAIL(do_post_traverse_processing())) { LOG_WARN("failed to post traverse processing", K(ret)); diff --git a/src/sql/optimizer/ob_log_sort.cpp b/src/sql/optimizer/ob_log_sort.cpp index b4bc63cad..ae81cd2a7 100644 --- a/src/sql/optimizer/ob_log_sort.cpp +++ b/src/sql/optimizer/ob_log_sort.cpp @@ -670,7 +670,7 @@ int ObLogSort::try_allocate_pushdown_topn_runtime_filter() LOG_WARN("fail to generate p2p dh id", K(ret)); } else { (void)topn_filter_info_.init(p2p_sequence_id, pushdown_topn_filter_expr, effective_sk_cnt, - tsc_has_exchange); + tsc_has_exchange, node); } } diff --git a/src/sql/optimizer/ob_log_sort.h b/src/sql/optimizer/ob_log_sort.h index 7fefb8a47..1c681e036 100644 --- a/src/sql/optimizer/ob_log_sort.h +++ b/src/sql/optimizer/ob_log_sort.h @@ -27,16 +27,17 @@ struct ObTopNFilterInfo public: ObTopNFilterInfo() : enabled_(false), p2p_sequence_id_(OB_INVALID_ID), pushdown_topn_filter_expr_(nullptr), - effective_sk_cnt_(0), is_shuffle_(false) + effective_sk_cnt_(0), is_shuffle_(false), topn_filter_node_(NULL) {} inline void init(int64_t p2p_sequence_id, ObRawExpr *pushdown_topn_filter_expr, - int64_t effective_sk_cnt, bool is_shuffle) + int64_t effective_sk_cnt, bool is_shuffle, ObLogicalOperator* node) { p2p_sequence_id_ = p2p_sequence_id; pushdown_topn_filter_expr_ = pushdown_topn_filter_expr; effective_sk_cnt_ = effective_sk_cnt; is_shuffle_ = is_shuffle; enabled_ = true; + topn_filter_node_ = node; } TO_STRING_KV(K_(enabled), K_(p2p_sequence_id), KP_(pushdown_topn_filter_expr), K_(effective_sk_cnt), K_(is_shuffle)); @@ -49,6 +50,7 @@ public: int64_t effective_sk_cnt_; // the topn sort op and the tsc op not in same dfo, need shuffle bool is_shuffle_; + ObLogicalOperator *topn_filter_node_; }; class ObLogSort : public ObLogicalOperator @@ -145,6 +147,7 @@ public: inline bool is_shuffle_pd_topn_filter() { return topn_filter_info_.is_shuffle_; } int try_allocate_pushdown_topn_runtime_filter(); int check_use_child_ordering(bool &used, int64_t &inherit_child_ordering_index); + ObLogicalOperator *get_topn_filter_node() const { return topn_filter_info_.topn_filter_node_; } protected: virtual int inner_replace_op_exprs(ObRawExprReplacer &replacer); int est_sort_key_width(); diff --git a/src/sql/optimizer/ob_log_table_scan.cpp b/src/sql/optimizer/ob_log_table_scan.cpp index f2a156218..f3790eecd 100644 --- a/src/sql/optimizer/ob_log_table_scan.cpp +++ b/src/sql/optimizer/ob_log_table_scan.cpp @@ -2331,7 +2331,9 @@ int ObLogTableScan::print_outline_data(PlanText &plan_text) int64_t index_prefix = index_prefix_; ObItemType index_type = T_INDEX_HINT; const ObDMLStmt *stmt = NULL; - if (OB_ISNULL(get_plan()) || OB_ISNULL(stmt = get_plan()->get_stmt())) { + bool use_desc_hint = get_scan_direction() == default_desc_direction(); + if (OB_ISNULL(get_plan()) || OB_ISNULL(stmt = get_plan()->get_stmt()) || + OB_ISNULL(stmt->get_query_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected NULl", K(ret), K(get_plan()), K(stmt)); } else if (OB_FAIL(stmt->get_qb_name(qb_name))) { @@ -2348,19 +2350,22 @@ int ObLogTableScan::print_outline_data(PlanText &plan_text) LOG_WARN("failed to print table parallel hint", K(ret)); } } + if (OB_SUCC(ret)) { + use_desc_hint &= stmt->get_query_ctx()->check_opt_compat_version(COMPAT_VERSION_4_3_5); + } if (OB_FAIL(ret)) { } else if (is_skip_scan()) { - index_type = T_INDEX_SS_HINT; + index_type = use_desc_hint ? T_INDEX_SS_DESC_HINT : T_INDEX_SS_HINT; if (ref_table_id_ == index_table_id_) { index_name = &ObIndexHint::PRIMARY_KEY; } else { index_name = &get_index_name(); } - } else if (ref_table_id_ == index_table_id_ && index_prefix < 0) { + } else if (ref_table_id_ == index_table_id_ && index_prefix < 0 && !use_desc_hint) { index_type = T_FULL_HINT; index_name = &ObIndexHint::PRIMARY_KEY; } else { - index_type = T_INDEX_HINT; + index_type = use_desc_hint ? T_INDEX_DESC_HINT : T_INDEX_HINT; if (ref_table_id_ == index_table_id_) { index_name = &ObIndexHint::PRIMARY_KEY; } else { @@ -2466,16 +2471,17 @@ int ObLogTableScan::print_used_hint(PlanText &plan_text) ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected log index hint", K(ret), K(*table_hint)); } else if (table_hint->is_use_index_hint()) {// print used use index hint + const ObIndexHint *index_hint = NULL; if (ObOptimizerUtil::find_item(table_hint->index_list_, index_table_id_, &idx)) { if (OB_UNLIKELY(idx < 0 || idx >= table_hint->index_list_.count()) - || OB_ISNULL(hint = table_hint->index_hints_.at(idx))) { + || OB_ISNULL(index_hint = static_cast(table_hint->index_hints_.at(idx)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected idx", K(ret), K(idx), K(table_hint->index_list_)); - } else if (!is_skip_scan() && T_INDEX_SS_HINT == hint->get_hint_type()) { + } else if (!is_skip_scan() && index_hint->use_skip_scan()) { /* is not index skip scan but exist index_ss hint */ - } else if (hint->is_trans_added()) { + } else if (index_hint->is_trans_added()) { //do nothing - } else if (OB_FAIL(hint->print_hint(plan_text))) { + } else if (OB_FAIL(index_hint->print_hint(plan_text))) { LOG_WARN("failed to print index hint", K(ret), K(*hint)); } } @@ -4166,3 +4172,33 @@ int ObLogTableScan::copy_gen_col_range_exprs() } return ret; } + +int ObLogTableScan::try_adjust_scan_direction(const ObIArray &sort_keys) +{ + int ret = OB_SUCCESS; + bool order_used = false; + const AccessPath *path = NULL; + if (OB_ISNULL(path = get_access_path())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(path)); + } else if (sort_keys.empty() || path->ordering_.empty() || + path->force_direction_ || use_batch()) { + // do nothing + } else if (OB_FAIL(check_op_orderding_used_by_parent(order_used))) { + LOG_WARN("failed to check op ordering", K(ret)); + } else if (!order_used) { + const OrderItem &first_sortkey = sort_keys.at(0); + bool found = false; + bool need_reverse = false; + for (int64_t i = 0; !found && i < path->ordering_.count(); i ++) { + const OrderItem &path_order = path->ordering_.at(i); + if (path_order.expr_ == first_sortkey.expr_) { + found = true; + } + } + if (OB_SUCC(ret) && found) { + set_scan_direction(first_sortkey.order_type_); + } + } + return ret; +} diff --git a/src/sql/optimizer/ob_log_table_scan.h b/src/sql/optimizer/ob_log_table_scan.h index 1467d13d6..4a9006471 100644 --- a/src/sql/optimizer/ob_log_table_scan.h +++ b/src/sql/optimizer/ob_log_table_scan.h @@ -745,6 +745,7 @@ public: int copy_gen_col_range_exprs(); inline bool need_replace_gen_column() { return !(is_index_scan() && !(get_index_back())); } + int try_adjust_scan_direction(const ObIArray &sort_keys); private: // member functions //called when index_back_ set int pick_out_query_range_exprs(); diff --git a/src/sql/optimizer/ob_logical_operator.cpp b/src/sql/optimizer/ob_logical_operator.cpp index 89b28b7db..9ed06c95a 100644 --- a/src/sql/optimizer/ob_logical_operator.cpp +++ b/src/sql/optimizer/ob_logical_operator.cpp @@ -1577,6 +1577,19 @@ int ObLogicalOperator::do_pre_traverse_operation(const TraverseOp &op, void *ctx } break; } + case ADJUST_SCAN_DIRECTION: { + if (LOG_SORT == get_type()) { + ObLogSort *log_sort = static_cast(this); + if (NULL != log_sort->get_topn_filter_node() && + LOG_TABLE_SCAN == log_sort->get_topn_filter_node()->get_type()) { + ObLogTableScan *log_tsc = static_cast(log_sort->get_topn_filter_node()); + if (OB_FAIL(log_tsc->try_adjust_scan_direction(log_sort->get_sort_keys()))) { + LOG_WARN("failed to adjust table scan direction", K(ret)); + } + } + } + break; + } default: { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected access of default branch", K(op), K(ret)); @@ -1718,6 +1731,9 @@ int ObLogicalOperator::do_post_traverse_operation(const TraverseOp &op, void *ct } break; } + case ADJUST_SCAN_DIRECTION: { + break; + } default: break; } diff --git a/src/sql/optimizer/ob_optimizer.h b/src/sql/optimizer/ob_optimizer.h index 2999a80b5..70c40bd53 100644 --- a/src/sql/optimizer/ob_optimizer.h +++ b/src/sql/optimizer/ob_optimizer.h @@ -89,6 +89,7 @@ namespace sql COLLECT_BATCH_EXEC_PARAM, ALLOC_OP, + ADJUST_SCAN_DIRECTION, TRAVERSE_OP_END }; diff --git a/src/sql/parser/sql_parser_mysql_mode.l b/src/sql/parser/sql_parser_mysql_mode.l index a331bbf0a..76223cd98 100644 --- a/src/sql/parser/sql_parser_mysql_mode.l +++ b/src/sql/parser/sql_parser_mysql_mode.l @@ -998,6 +998,8 @@ Timestamp{whitespace}?\"[^\"]*\" { } } INDEX { return INDEX_HINT; } +INDEX_ASC { return INDEX_ASC_HINT; } +INDEX_DESC { return INDEX_DESC_HINT; } NO_INDEX { return NO_INDEX_HINT; } UNION_MERGE { return UNION_MERGE_HINT; } USE_DAS { return USE_DAS_HINT; } diff --git a/src/sql/parser/sql_parser_mysql_mode.y b/src/sql/parser/sql_parser_mysql_mode.y index 7bb65b717..fb661db41 100644 --- a/src/sql/parser/sql_parser_mysql_mode.y +++ b/src/sql/parser/sql_parser_mysql_mode.y @@ -183,7 +183,7 @@ COALESCE_AGGR NO_COALESCE_AGGR WITH_PULLUP WO_PULLUP MV_REWRITE NO_MV_REWRITE TRANSFORM_DISTINCT_AGG NO_TRANSFORM_DISTINCT_AGG DECORRELATE NO_DECORRELATE // optimize hint -INDEX_HINT FULL_HINT NO_INDEX_HINT USE_DAS_HINT NO_USE_DAS_HINT UNION_MERGE_HINT +INDEX_HINT INDEX_ASC_HINT INDEX_DESC_HINT FULL_HINT NO_INDEX_HINT USE_DAS_HINT NO_USE_DAS_HINT UNION_MERGE_HINT INDEX_SS_HINT INDEX_SS_ASC_HINT INDEX_SS_DESC_HINT USE_COLUMN_STORE_HINT NO_USE_COLUMN_STORE_HINT LEADING_HINT ORDERED @@ -11825,6 +11825,14 @@ INDEX_HINT '(' qb_name_option relation_factor_in_hint NAME_OB opt_index_prefix ' { malloc_non_terminal_node($$, result->malloc_pool_, T_INDEX_HINT, 4, $3, $4, $5,$6); } +| INDEX_ASC_HINT '(' qb_name_option relation_factor_in_hint NAME_OB opt_index_prefix ')' +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_INDEX_ASC_HINT, 4, $3, $4, $5,$6); +} +| INDEX_DESC_HINT '(' qb_name_option relation_factor_in_hint NAME_OB opt_index_prefix ')' +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_INDEX_DESC_HINT, 4, $3, $4, $5,$6); +} | NO_INDEX_HINT '(' qb_name_option relation_factor_in_hint NAME_OB ')' { malloc_non_terminal_node($$, result->malloc_pool_, T_NO_INDEX_HINT, 3, $3, $4, $5); diff --git a/src/sql/resolver/dml/ob_dml_resolver.cpp b/src/sql/resolver/dml/ob_dml_resolver.cpp index 15f9fa239..0296f94c3 100755 --- a/src/sql/resolver/dml/ob_dml_resolver.cpp +++ b/src/sql/resolver/dml/ob_dml_resolver.cpp @@ -15191,7 +15191,9 @@ int ObDMLResolver::resolve_optimize_hint(const ParseNode &hint_node, case T_INDEX_SS_ASC_HINT: case T_INDEX_SS_DESC_HINT: case T_USE_COLUMN_STORE_HINT: - case T_NO_USE_COLUMN_STORE_HINT: { + case T_NO_USE_COLUMN_STORE_HINT: + case T_INDEX_ASC_HINT: + case T_INDEX_DESC_HINT: { if (OB_FAIL(resolve_index_hint(hint_node, opt_hint))) { LOG_WARN("failed to resolve index hint", K(ret)); } @@ -15375,12 +15377,14 @@ int ObDMLResolver::resolve_index_hint(const ParseNode &index_node, LOG_WARN("unexpected index hint", K(ret), K(index_node.type_), K(index_node.num_child_), K(index_name_node)); } else { - //T_NO_INDEX or T_INDEX_HINT + //T_NO_INDEX or T_INDEX_HINT or T_INDEX_ASC_HINT or T_INDEX_DESC_HINT index_hint->set_qb_name(qb_name); index_hint->get_index_name().assign_ptr(index_name_node->str_value_, static_cast(index_name_node->str_len_)); opt_hint = index_hint; - if (T_INDEX_HINT == index_hint->get_hint_type()) { + if (T_INDEX_HINT == index_hint->get_hint_type() || + T_INDEX_ASC_HINT == index_hint->get_hint_type() || + T_INDEX_DESC_HINT == index_hint->get_hint_type()) { if (OB_UNLIKELY(4 != index_node.num_child_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected index hint", K(ret), K(index_node.type_), K(index_node.num_child_), diff --git a/src/sql/resolver/dml/ob_hint.cpp b/src/sql/resolver/dml/ob_hint.cpp index 16930d7c0..8b8584fa6 100644 --- a/src/sql/resolver/dml/ob_hint.cpp +++ b/src/sql/resolver/dml/ob_hint.cpp @@ -1355,6 +1355,8 @@ const char* ObHint::get_hint_name(ObItemType type, bool is_enable_hint /* defaul case T_PQ_SUBQUERY: return "PQ_SUBQUERY"; case T_PQ_GBY_HINT: return "PQ_GBY"; case T_PQ_DISTINCT_HINT: return "PQ_DISTINCT"; + case T_INDEX_ASC_HINT: return "INDEX_ASC"; + case T_INDEX_DESC_HINT: return "INDEX_DESC"; default: return NULL; } } @@ -2335,7 +2337,8 @@ int ObIndexHint::print_hint_desc(PlanText &plan_text) const /* do nothing */ } else if (OB_FAIL(BUF_PRINTF(" \"%.*s\"", index_name_.length(), index_name_.ptr()))) { LOG_WARN("fail to print index name", K(ret)); - } else if (T_INDEX_HINT != hint_type_ || index_prefix_ < 0) { + } else if ((T_INDEX_HINT != hint_type_ && T_INDEX_ASC_HINT != hint_type_ && T_INDEX_DESC_HINT != hint_type_) + || index_prefix_ < 0) { //do nothing } else if (OB_FAIL(BUF_PRINTF(" %ld", index_prefix_))) { LOG_WARN("fail to print index prefix", K(ret)); diff --git a/src/sql/resolver/dml/ob_hint.h b/src/sql/resolver/dml/ob_hint.h index ff2317a8c..6cebf2e13 100644 --- a/src/sql/resolver/dml/ob_hint.h +++ b/src/sql/resolver/dml/ob_hint.h @@ -1031,10 +1031,28 @@ public: int64_t &get_index_prefix() { return index_prefix_; } const int64_t &get_index_prefix() const { return index_prefix_; } bool is_use_index_hint() const { return T_NO_INDEX_HINT != get_hint_type(); } - bool use_skip_scan() const { return T_INDEX_SS_HINT == get_hint_type(); } + bool use_skip_scan() const { return T_INDEX_SS_HINT == get_hint_type() || + T_INDEX_SS_ASC_HINT == get_hint_type() || + T_INDEX_SS_DESC_HINT == get_hint_type(); } bool is_match_index(const ObCollationType cs_type, const TableItem &ref_table, const ObTableSchema &index_schema) const; + bool is_asc_hint() const + { + return T_INDEX_ASC_HINT == get_hint_type() || + T_INDEX_SS_ASC_HINT == get_hint_type(); + } + bool is_desc_hint() const + { + return T_INDEX_DESC_HINT == get_hint_type() || + T_INDEX_SS_DESC_HINT == get_hint_type(); + } + bool is_unordered_hint() const + { + return T_INDEX_HINT == get_hint_type() || + T_INDEX_SS_HINT == get_hint_type() || + T_FULL_HINT == get_hint_type(); + } INHERIT_TO_STRING_KV("ObHint", ObHint, K_(table), K_(index_name), K_(index_prefix)); diff --git a/src/sql/resolver/dml/ob_sql_hint.cpp b/src/sql/resolver/dml/ob_sql_hint.cpp index 905c61d3f..091bea1a2 100644 --- a/src/sql/resolver/dml/ob_sql_hint.cpp +++ b/src/sql/resolver/dml/ob_sql_hint.cpp @@ -1942,6 +1942,39 @@ int ObLogPlanHint::check_use_skip_scan(uint64_t table_id, return ret; } +int ObLogPlanHint::check_scan_direction(const ObQueryCtx &ctx, + uint64_t table_id, + uint64_t index_id, + ObOrderDirection &direction) const +{ + int ret = OB_SUCCESS; + direction = ObOrderDirection::UNORDERED; + const LogTableHint *log_table_hint = get_log_table_hint(table_id); + int64_t pos = OB_INVALID_INDEX; + static const uint64_t index_desc_enable_version = COMPAT_VERSION_4_3_5; + if (!ctx.check_opt_compat_version(index_desc_enable_version)) { + direction = ObOrderDirection::UNORDERED; + } else if (NULL != log_table_hint && + ObOptimizerUtil::find_item(log_table_hint->index_list_, index_id, &pos)) { + const ObIndexHint *hint = NULL; + if (OB_UNLIKELY(pos >= log_table_hint->index_hints_.count() || pos < 0) + || OB_ISNULL(hint = log_table_hint->index_hints_.at(pos))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected pos", K(ret), K(pos), K(log_table_hint->index_hints_.count()), K(hint)); + } else if (hint->is_asc_hint()) { + direction = default_asc_direction(); + } else if (hint->is_desc_hint()) { + direction = default_desc_direction(); + } else if (is_outline_data_ && + hint->is_unordered_hint()) { + direction = default_asc_direction(); + } else { + direction = ObOrderDirection::UNORDERED; + } + } + return ret; +} + const ObTableDynamicSamplingHint *ObLogPlanHint::get_dynamic_sampling_hint(uint64_t table_id) const { const LogTableHint *log_table_hint = get_log_table_hint(table_id); @@ -2498,7 +2531,11 @@ int LogTableHint::init_index_hints(ObSqlSchemaGuard &schema_guard) if (OB_SUCC(ret) && (!index_name.empty())) { int64_t no_index_hint_pos = OB_INVALID_INDEX; int64_t index_hint_pos = OB_INVALID_INDEX; + int64_t index_asc_hint_pos = OB_INVALID_INDEX; + int64_t index_desc_hint_pos = OB_INVALID_INDEX; int64_t index_ss_hint_pos = OB_INVALID_INDEX; + int64_t index_ss_asc_hint_pos = OB_INVALID_INDEX; + int64_t index_ss_desc_hint_pos = OB_INVALID_INDEX; const uint64_t N = index_hints_.count(); const ObIndexHint *index_hint = NULL; for (int64_t hint_i = 0; OB_SUCC(ret) && hint_i < N; ++hint_i) { @@ -2512,10 +2549,40 @@ int LogTableHint::init_index_hints(ObSqlSchemaGuard &schema_guard) /* do nothing */ } else if (T_NO_INDEX_HINT == index_hint->get_hint_type()) { no_index_hint_pos = hint_i; - } else if (T_INDEX_SS_HINT == index_hint->get_hint_type()) { - index_ss_hint_pos = hint_i; + } else if (index_hint->use_skip_scan()) { + if (index_hint->is_asc_hint()) { + index_ss_asc_hint_pos = hint_i; + } else if (index_hint->is_desc_hint()) { + index_ss_desc_hint_pos = hint_i; + } else { + index_ss_hint_pos = hint_i; + } } else { - index_hint_pos = hint_i; + if (index_hint->is_asc_hint()) { + index_asc_hint_pos = hint_i; + } else if (index_hint->is_desc_hint()) { + index_desc_hint_pos = hint_i; + } else { + index_hint_pos = hint_i; + } + } + } + if (OB_SUCC(ret)) { + if (OB_INVALID_INDEX != index_asc_hint_pos && + OB_INVALID_INDEX != index_desc_hint_pos) { + // ignore both asc and desc hint if both are present + } else if (OB_INVALID_INDEX != index_asc_hint_pos) { + index_hint_pos = index_asc_hint_pos; + } else if (OB_INVALID_INDEX != index_desc_hint_pos) { + index_hint_pos = index_desc_hint_pos; + } + if (OB_INVALID_INDEX != index_ss_asc_hint_pos && + OB_INVALID_INDEX != index_ss_desc_hint_pos) { + // ignore both asc and desc hint if both are present + } else if (OB_INVALID_INDEX != index_ss_asc_hint_pos) { + index_ss_hint_pos = index_ss_asc_hint_pos; + } else if (OB_INVALID_INDEX != index_ss_desc_hint_pos) { + index_ss_hint_pos = index_ss_desc_hint_pos; } } if (OB_FAIL(ret)) { @@ -2713,7 +2780,9 @@ int LogTableHint::get_index_prefix(const uint64_t index_id, int64_t &index_prefi } else if (OB_ISNULL(index_hints_.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null", K(ret), K(i), K(index_hints_)); - } else if (T_INDEX_HINT == index_hints_.at(i)->get_hint_type()) { + } else if (T_INDEX_HINT == index_hints_.at(i)->get_hint_type() || + T_INDEX_ASC_HINT == index_hints_.at(i)->get_hint_type() || + T_INDEX_DESC_HINT == index_hints_.at(i)->get_hint_type()) { index_prefix = index_hints_.at(i)->get_index_prefix(); } } diff --git a/src/sql/resolver/dml/ob_sql_hint.h b/src/sql/resolver/dml/ob_sql_hint.h index a18acbc6c..36c397060 100644 --- a/src/sql/resolver/dml/ob_sql_hint.h +++ b/src/sql/resolver/dml/ob_sql_hint.h @@ -464,6 +464,10 @@ struct ObLogPlanHint int check_use_skip_scan(uint64_t table_id, uint64_t index_id, bool &force_skip_scan, bool &force_no_skip_scan) const; + int check_scan_direction(const ObQueryCtx &ctx, + uint64_t table_id, + uint64_t index_id, + ObOrderDirection &direction) const; const LogJoinHint* get_join_hint(const ObRelIds &join_tables) const; const ObIArray &get_join_hints() const { return join_hints_; } SetAlgo get_valid_set_algo() const; diff --git a/src/sql/rewrite/ob_transform_late_materialization.cpp b/src/sql/rewrite/ob_transform_late_materialization.cpp index 3adb750d4..5dab3f915 100644 --- a/src/sql/rewrite/ob_transform_late_materialization.cpp +++ b/src/sql/rewrite/ob_transform_late_materialization.cpp @@ -371,6 +371,8 @@ int ObTransformLateMaterialization::get_accessible_index(const ObSelectStmt &sel } else if (FALSE_IT(index_hint = static_cast(opt_hints.at(i)))) { /* do nothing */ } else if (T_INDEX_HINT == index_hint->get_hint_type() || + T_INDEX_ASC_HINT == index_hint->get_hint_type() || + T_INDEX_DESC_HINT == index_hint->get_hint_type() || T_INDEX_SS_HINT == index_hint->get_hint_type() || T_INDEX_SS_ASC_HINT == index_hint->get_hint_type() || T_INDEX_SS_DESC_HINT == index_hint->get_hint_type()) { @@ -962,6 +964,8 @@ int ObTransformLateMaterialization::generate_late_materialization_hint( } else if (hint->is_access_path_hint()) { ObIndexHint *index_hint = static_cast(hint); if ((T_INDEX_HINT == index_hint->get_hint_type() || + T_INDEX_ASC_HINT == index_hint->get_hint_type() || + T_INDEX_DESC_HINT == index_hint->get_hint_type() || T_INDEX_SS_HINT == index_hint->get_hint_type() || T_INDEX_SS_ASC_HINT == index_hint->get_hint_type() || T_INDEX_SS_DESC_HINT == index_hint->get_hint_type() || @@ -982,6 +986,8 @@ int ObTransformLateMaterialization::generate_late_materialization_hint( } else if (hint->is_access_path_hint()) { ObIndexHint *index_hint = static_cast(hint); if ((T_INDEX_HINT == index_hint->get_hint_type() || + T_INDEX_ASC_HINT == index_hint->get_hint_type() || + T_INDEX_DESC_HINT == index_hint->get_hint_type() || T_INDEX_SS_HINT == index_hint->get_hint_type() || T_INDEX_SS_ASC_HINT == index_hint->get_hint_type() || T_INDEX_SS_DESC_HINT == index_hint->get_hint_type() ||