📄 pars0opt.c
字号:
} else if (op == '>') { ut_a(asc); return(PAGE_CUR_G); } else if (op == PARS_GE_TOKEN) { ut_a(asc); return(PAGE_CUR_GE); } else if (op == PARS_LE_TOKEN) { ut_a(!asc); return(PAGE_CUR_LE); } else { ut_error; } return(0);}/***********************************************************************Determines if a node is an argument node of a function node. */staticiboolopt_is_arg(/*=======*/ /* out: TRUE if is an argument */ que_node_t* arg_node, /* in: possible argument node */ func_node_t* func_node) /* in: function node */{ que_node_t* arg; arg = func_node->args; while (arg) { if (arg == arg_node) { return(TRUE); } arg = que_node_get_next(arg); } return(FALSE);}/***********************************************************************Decides if the fetching of rows should be made in a descending order, andalso checks that the chosen query plan produces a result which satisfiesthe order-by. */staticvoidopt_check_order_by(/*===============*/ sel_node_t* sel_node) /* in: select node; asserts an error if the plan does not agree with the order-by */{ order_node_t* order_node; dict_table_t* order_table; ulint order_col_no; plan_t* plan; ulint i; if (!sel_node->order_by) { return; } order_node = sel_node->order_by; order_col_no = order_node->column->col_no; order_table = order_node->column->table; /* If there is an order-by clause, the first non-exactly matched field in the index used for the last table in the table list should be the column defined in the order-by clause, and for all the other tables we should get only at most a single row, otherwise we cannot presently calculate the order-by, as we have no sort utility */ for (i = 0; i < sel_node->n_tables; i++) { plan = sel_node_get_nth_plan(sel_node, i); if (i < sel_node->n_tables - 1) { ut_a(dict_index_get_n_unique(plan->index) <= plan->n_exact_match); } else { ut_a(plan->table == order_table); ut_a((dict_index_get_n_unique(plan->index) <= plan->n_exact_match) || (dict_index_get_nth_col_no(plan->index, plan->n_exact_match) == order_col_no)); } }}/***********************************************************************Optimizes a select. Decides which indexes to tables to use. The tablesare accessed in the order that they were written to the FROM part in theselect statement. */staticvoidopt_search_plan_for_table(/*======================*/ sel_node_t* sel_node, /* in: parsed select node */ ulint i, /* in: this is the ith table */ dict_table_t* table) /* in: table */{ plan_t* plan; dict_index_t* index; dict_index_t* best_index; ulint n_fields; ulint goodness; ulint last_op = 75946965; /* Eliminate a Purify warning */ ulint best_goodness; ulint best_last_op = 0; /* remove warning */ ulint mix_id_pos; que_node_t* index_plan[256]; que_node_t* best_index_plan[256]; plan = sel_node_get_nth_plan(sel_node, i); plan->table = table; plan->asc = sel_node->asc; plan->pcur_is_open = FALSE; plan->cursor_at_end = FALSE; /* Calculate goodness for each index of the table */ index = dict_table_get_first_index(table); best_index = index; /* Eliminate compiler warning */ best_goodness = 0; /* should be do ... until ? comment by Jani */ while (index) { goodness = opt_calc_index_goodness(index, sel_node, i, index_plan, &last_op); if (goodness > best_goodness) { best_index = index; best_goodness = goodness; n_fields = opt_calc_n_fields_from_goodness(goodness); ut_memcpy(best_index_plan, index_plan, n_fields * sizeof(void*)); best_last_op = last_op; } index = dict_table_get_next_index(index); } plan->index = best_index; n_fields = opt_calc_n_fields_from_goodness(best_goodness); if (n_fields == 0) { plan->tuple = NULL; plan->n_exact_match = 0; } else { plan->tuple = dtuple_create(pars_sym_tab_global->heap, n_fields); dict_index_copy_types(plan->tuple, plan->index, n_fields); plan->tuple_exps = mem_heap_alloc(pars_sym_tab_global->heap, n_fields * sizeof(void*)); ut_memcpy(plan->tuple_exps, best_index_plan, n_fields * sizeof(void*)); if (best_last_op == '=') { plan->n_exact_match = n_fields; } else { plan->n_exact_match = n_fields - 1; } plan->mode = opt_op_to_search_mode(sel_node->asc, best_last_op); } if ((best_index->type & DICT_CLUSTERED) && (plan->n_exact_match >= dict_index_get_n_unique(best_index))) { plan->unique_search = TRUE; } else { plan->unique_search = FALSE; } if ((table->type != DICT_TABLE_ORDINARY) && (best_index->type & DICT_CLUSTERED)) { plan->mixed_index = TRUE; mix_id_pos = table->mix_len; if (mix_id_pos < n_fields) { /* We have to add the mix id as a (string) literal expression to the tuple_exps */ plan->tuple_exps[mix_id_pos] = sym_tab_add_str_lit(pars_sym_tab_global, table->mix_id_buf, table->mix_id_len); } } else { plan->mixed_index = FALSE; } plan->old_vers_heap = NULL; btr_pcur_init(&(plan->pcur)); btr_pcur_init(&(plan->clust_pcur));}/***********************************************************************Looks at a comparison condition and decides if it can, and need, be tested fora table AFTER the table has been accessed. */staticulintopt_classify_comparison(/*====================*/ /* out: OPT_NOT_COND if not for this table, else OPT_END_COND, OPT_TEST_COND, or OPT_SCROLL_COND, where the last means that the condition need not be tested, except when scroll cursors are used */ sel_node_t* sel_node, /* in: select node */ ulint i, /* in: ith table in the join */ func_node_t* cond) /* in: comparison condition */{ plan_t* plan; ulint n_fields; ulint op; ulint j; ut_ad(cond && sel_node); plan = sel_node_get_nth_plan(sel_node, i); /* Check if the condition is determined after the ith table has been accessed, but not after the i - 1:th */ if (!opt_check_exp_determined_before(cond, sel_node, i + 1)) { return(OPT_NOT_COND); } if ((i > 0) && opt_check_exp_determined_before(cond, sel_node, i)) { return(OPT_NOT_COND); } /* If the condition is an exact match condition used in constructing the search tuple, it is classified as OPT_END_COND */ if (plan->tuple) { n_fields = dtuple_get_n_fields(plan->tuple); } else { n_fields = 0; } for (j = 0; j < plan->n_exact_match; j++) { if (opt_is_arg(plan->tuple_exps[j], cond)) { return(OPT_END_COND); } } /* If the condition is an non-exact match condition used in constructing the search tuple, it is classified as OPT_SCROLL_COND. When the cursor is positioned, and if a non-scroll cursor is used, there is no need to test this condition; if a scroll cursor is used the testing is necessary when the cursor is reversed. */ if ((n_fields > plan->n_exact_match) && opt_is_arg(plan->tuple_exps[n_fields - 1], cond)) { return(OPT_SCROLL_COND); } /* If the condition is a non-exact match condition on the first field in index for which there is no exact match, and it limits the search range from the opposite side of the search tuple already BEFORE we access the table, it is classified as OPT_END_COND */ if ((dict_index_get_n_fields(plan->index) > plan->n_exact_match) && opt_look_for_col_in_comparison_before( OPT_COMPARISON, dict_index_get_nth_col_no(plan->index, plan->n_exact_match), cond, sel_node, i, &op)) { if (sel_node->asc && ((op == '<') || (op == PARS_LE_TOKEN))) { return(OPT_END_COND); } if (!sel_node->asc && ((op == '>') || (op == PARS_GE_TOKEN))) { return(OPT_END_COND); } } /* Otherwise, cond is classified as OPT_TEST_COND */ return(OPT_TEST_COND);}/***********************************************************************Recursively looks for test conditions for a table in a join. */staticvoidopt_find_test_conds(/*================*/ sel_node_t* sel_node, /* in: select node */ ulint i, /* in: ith table in the join */ func_node_t* cond) /* in: conjunction of search conditions or NULL */{ func_node_t* new_cond; ulint class; plan_t* plan; if (cond == NULL) { return; } if (cond->func == PARS_AND_TOKEN) { new_cond = cond->args; opt_find_test_conds(sel_node, i, new_cond); new_cond = que_node_get_next(new_cond); opt_find_test_conds(sel_node, i, new_cond); return; } plan = sel_node_get_nth_plan(sel_node, i); class = opt_classify_comparison(sel_node, i, cond); if (class == OPT_END_COND) { UT_LIST_ADD_LAST(cond_list, plan->end_conds, cond); } else if (class == OPT_TEST_COND) { UT_LIST_ADD_LAST(cond_list, plan->other_conds, cond); }}/***********************************************************************Normalizes a list of comparison conditions so that a column of the tableappears on the left side of the comparison if possible. This is accomplishedby switching the arguments of the operator. */staticvoidopt_normalize_cmp_conds(/*====================*/ func_node_t* cond, /* in: first in a list of comparison conditions, or NULL */ dict_table_t* table) /* in: table */{ que_node_t* arg1; que_node_t* arg2; sym_node_t* sym_node; while (cond) { arg1 = cond->args; arg2 = que_node_get_next(arg1); if (que_node_get_type(arg2) == QUE_NODE_SYMBOL) { sym_node = arg2; if ((sym_node->token_type == SYM_COLUMN) && (sym_node->table == table)) { /* Switch the order of the arguments */ cond->args = arg2; que_node_list_add_last(NULL, arg2); que_node_list_add_last(arg2, arg1); /* Invert the operator */ cond->func = opt_invert_cmp_op(cond->func); } } cond = UT_LIST_GET_NEXT(cond_list, cond); }} /***********************************************************************Finds out the search condition conjuncts we can, and need, to test as the ithtable in a join is accessed. The search tuple can eliminate the need to testsome conjuncts. */staticvoidopt_determine_and_normalize_test_conds(/*===================================*/ sel_node_t* sel_node, /* in: select node */ ulint i) /* in: ith table in the join */{ plan_t* plan; plan = sel_node_get_nth_plan(sel_node, i); UT_LIST_INIT(plan->end_conds); UT_LIST_INIT(plan->other_conds); /* Recursively go through the conjuncts and classify them */ opt_find_test_conds(sel_node, i, sel_node->search_cond); opt_normalize_cmp_conds(UT_LIST_GET_FIRST(plan->end_conds), plan->table);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -