📄 pars0opt.c
字号:
ut_a(UT_LIST_GET_LEN(plan->end_conds) >= plan->n_exact_match);}/***********************************************************************Looks for occurrences of the columns of the table in the query subgraph andadds them to the list of columns if an occurrence of the same column does notalready exist in the list. If the column is already in the list, puts a valueindirection to point to the occurrence in the column list, except if thecolumn occurrence we are looking at is in the column list, in which casenothing is done. */voidopt_find_all_cols(/*==============*/ ibool copy_val, /* in: if TRUE, new found columns are added as columns to copy */ dict_index_t* index, /* in: index of the table to use */ sym_node_list_t* col_list, /* in: base node of a list where to add new found columns */ plan_t* plan, /* in: plan or NULL */ que_node_t* exp) /* in: expression or condition or NULL */{ func_node_t* func_node; que_node_t* arg; sym_node_t* sym_node; sym_node_t* col_node; ulint col_pos; if (exp == NULL) { return; } if (que_node_get_type(exp) == QUE_NODE_FUNC) { func_node = exp; arg = func_node->args; while (arg) { opt_find_all_cols(copy_val, index, col_list, plan, arg); arg = que_node_get_next(arg); } return; } ut_a(que_node_get_type(exp) == QUE_NODE_SYMBOL); sym_node = exp; if (sym_node->token_type != SYM_COLUMN) { return; } if (sym_node->table != index->table) { return; } /* Look for an occurrence of the same column in the plan column list */ col_node = UT_LIST_GET_FIRST(*col_list); while (col_node) { if (col_node->col_no == sym_node->col_no) { if (col_node == sym_node) { /* sym_node was already in a list: do nothing */ return; } /* Put an indirection */ sym_node->indirection = col_node; sym_node->alias = col_node; return; } col_node = UT_LIST_GET_NEXT(col_var_list, col_node); } /* The same column did not occur in the list: add it */ UT_LIST_ADD_LAST(col_var_list, *col_list, sym_node); sym_node->copy_val = copy_val; /* Fill in the field_no fields in sym_node */ sym_node->field_nos[SYM_CLUST_FIELD_NO] = dict_index_get_nth_col_pos( dict_table_get_first_index(index->table), sym_node->col_no); if (!(index->type & DICT_CLUSTERED)) { ut_a(plan); col_pos = dict_index_get_nth_col_pos(index, sym_node->col_no); if (col_pos == ULINT_UNDEFINED) { plan->must_get_clust = TRUE; } sym_node->field_nos[SYM_SEC_FIELD_NO] = col_pos; }}/***********************************************************************Looks for occurrences of the columns of the table in conditions which arenot yet determined AFTER the join operation has fetched a row in the ithtable. The values for these column must be copied to dynamic memory forlater use. */staticvoidopt_find_copy_cols(/*===============*/ sel_node_t* sel_node, /* in: select node */ ulint i, /* in: ith table in the join */ func_node_t* search_cond) /* in: search condition or NULL */{ func_node_t* new_cond; plan_t* plan; if (search_cond == NULL) { return; } ut_ad(que_node_get_type(search_cond) == QUE_NODE_FUNC); if (search_cond->func == PARS_AND_TOKEN) { new_cond = search_cond->args; opt_find_copy_cols(sel_node, i, new_cond); new_cond = que_node_get_next(new_cond); opt_find_copy_cols(sel_node, i, new_cond); return; } if (!opt_check_exp_determined_before(search_cond, sel_node, i + 1)) { /* Any ith table columns occurring in search_cond should be copied, as this condition cannot be tested already on the fetch from the ith table */ plan = sel_node_get_nth_plan(sel_node, i); opt_find_all_cols(TRUE, plan->index, &(plan->columns), plan, search_cond); }}/***********************************************************************Classifies the table columns according to whether we use the column only whileholding the latch on the page, or whether we have to copy the column value todynamic memory. Puts the first occurrence of a column to either list in theplan node, and puts indirections to later occurrences of the column. */staticvoidopt_classify_cols(/*==============*/ sel_node_t* sel_node, /* in: select node */ ulint i) /* in: ith table in the join */{ plan_t* plan; que_node_t* exp; plan = sel_node_get_nth_plan(sel_node, i); /* The final value of the following field will depend on the environment of the select statement: */ plan->must_get_clust = FALSE; UT_LIST_INIT(plan->columns); /* All select list columns should be copied: therefore TRUE as the first argument */ exp = sel_node->select_list; while (exp) { opt_find_all_cols(TRUE, plan->index, &(plan->columns), plan, exp); exp = que_node_get_next(exp); } opt_find_copy_cols(sel_node, i, sel_node->search_cond); /* All remaining columns in the search condition are temporary columns: therefore FALSE */ opt_find_all_cols(FALSE, plan->index, &(plan->columns), plan, sel_node->search_cond);}/***********************************************************************Fills in the info in plan which is used in accessing a clustered indexrecord. The columns must already be classified for the plan node. */staticvoidopt_clust_access(/*=============*/ sel_node_t* sel_node, /* in: select node */ ulint n) /* in: nth table in select */{ plan_t* plan; dict_table_t* table; dict_index_t* clust_index; dict_index_t* index; dfield_t* dfield; mem_heap_t* heap; ulint n_fields; ulint pos; ulint i; plan = sel_node_get_nth_plan(sel_node, n); index = plan->index; /* The final value of the following field depends on the environment of the select statement: */ plan->no_prefetch = FALSE; if (index->type & DICT_CLUSTERED) { plan->clust_map = NULL; plan->clust_ref = NULL; return; } table = index->table; clust_index = dict_table_get_first_index(table); n_fields = dict_index_get_n_unique(clust_index); heap = pars_sym_tab_global->heap; plan->clust_ref = dtuple_create(heap, n_fields); dict_index_copy_types(plan->clust_ref, clust_index, n_fields); plan->clust_map = mem_heap_alloc(heap, n_fields * sizeof(ulint)); for (i = 0; i < n_fields; i++) { pos = dict_index_get_nth_field_pos(index, clust_index, i); ut_a(pos != ULINT_UNDEFINED); /* We optimize here only queries to InnoDB's internal system tables, and they should not contain column prefix indexes. */ if (dict_index_get_nth_field(index, pos)->prefix_len != 0 || dict_index_get_nth_field(clust_index, i) ->prefix_len != 0) { fprintf(stderr,"InnoDB: Error in pars0opt.c: table %s has prefix_len != 0\n", index->table_name); } *(plan->clust_map + i) = pos; ut_ad((pos != ULINT_UNDEFINED) || ((table->type == DICT_TABLE_CLUSTER_MEMBER) && (i == table->mix_len))); } if (table->type == DICT_TABLE_CLUSTER_MEMBER) { /* Preset the mix id field to the mix id constant */ dfield = dtuple_get_nth_field(plan->clust_ref, table->mix_len); dfield_set_data(dfield, mem_heap_alloc(heap, table->mix_id_len), table->mix_id_len); ut_memcpy(dfield_get_data(dfield), table->mix_id_buf, table->mix_id_len); }}/***********************************************************************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. */voidopt_search_plan(/*============*/ sel_node_t* sel_node) /* in: parsed select node */{ sym_node_t* table_node; dict_table_t* table; order_node_t* order_by; ulint i; sel_node->plans = mem_heap_alloc(pars_sym_tab_global->heap, sel_node->n_tables * sizeof(plan_t)); /* Analyze the search condition to find out what we know at each join stage about the conditions that the columns of a table should satisfy */ table_node = sel_node->table_list; if (sel_node->order_by == NULL) { sel_node->asc = TRUE; } else { order_by = sel_node->order_by; sel_node->asc = order_by->asc; } for (i = 0; i < sel_node->n_tables; i++) { table = table_node->table; /* Choose index through which to access the table */ opt_search_plan_for_table(sel_node, i, table); /* Determine the search condition conjuncts we can test at this table; normalize the end conditions */ opt_determine_and_normalize_test_conds(sel_node, i); table_node = que_node_get_next(table_node); } table_node = sel_node->table_list; for (i = 0; i < sel_node->n_tables; i++) { /* Classify the table columns into those we only need to access but not copy, and to those we must copy to dynamic memory */ opt_classify_cols(sel_node, i); /* Calculate possible info for accessing the clustered index record */ opt_clust_access(sel_node, i); table_node = que_node_get_next(table_node); } /* Check that the plan obeys a possible order-by clause: if not, an assertion error occurs */ opt_check_order_by(sel_node);#ifdef UNIV_SQL_DEBUG opt_print_query_plan(sel_node);#endif}/************************************************************************Prints info of a query plan. */voidopt_print_query_plan(/*=================*/ sel_node_t* sel_node) /* in: select node */{ plan_t* plan; ulint n_fields; ulint i; fputs("QUERY PLAN FOR A SELECT NODE\n", stderr); fputs(sel_node->asc ? "Asc. search; " : "Desc. search; ", stderr); if (sel_node->set_x_locks) { fputs("sets row x-locks; ", stderr); ut_a(sel_node->row_lock_mode == LOCK_X); ut_a(!sel_node->consistent_read); } else if (sel_node->consistent_read) { fputs("consistent read; ", stderr); } else { ut_a(sel_node->row_lock_mode == LOCK_S); fputs("sets row s-locks; ", stderr); } putc('\n', stderr); for (i = 0; i < sel_node->n_tables; i++) { plan = sel_node_get_nth_plan(sel_node, i); if (plan->tuple) { n_fields = dtuple_get_n_fields(plan->tuple); } else { n_fields = 0; } fputs("Table ", stderr); dict_index_name_print(stderr, NULL, plan->index); fprintf(stderr,"; exact m. %lu, match %lu, end conds %lu\n", (unsigned long) plan->n_exact_match, (unsigned long) n_fields, (unsigned long) UT_LIST_GET_LEN(plan->end_conds)); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -