diff options
author | Monty <monty@mariadb.org> | 2022-06-13 17:45:37 +0300 |
---|---|---|
committer | Monty <monty@mariadb.org> | 2022-07-10 15:09:32 +0300 |
commit | 964b9f30893e0c9e493cdac0c9501f4aa11998ca (patch) | |
tree | dcbbb6f118a4dca3d740c1cfb9200682df9da895 | |
parent | 47d05993c0281c9262b6cb789eeec401ad5b180d (diff) | |
download | mariadb-git-964b9f30893e0c9e493cdac0c9501f4aa11998ca.tar.gz |
Move join->emb_smj_nest setting to choose_plan()
This cleans up the interface for choose_plan() as it is not depending
on setting join->emb_sj_nest.
choose_plan() now sets up join->emb_sj_nest and join->allowed_tables before
calling optimize_straight_join() and best_extension_by_limited_search().
Other things:
- Converted some 'if' to DBUG_ASSERT() as these should always be true.
- Calculate 'allowed_tables' in choose_plan() as this never changes in
the childs.
- Added assert to check that next_emb->nested_join->n_tables doesn't
get to a wrong value.
- Documented some variables in sql_select.h
-rw-r--r-- | sql/opt_split.cc | 2 | ||||
-rw-r--r-- | sql/opt_subselect.cc | 4 | ||||
-rw-r--r-- | sql/sql_select.cc | 59 | ||||
-rw-r--r-- | sql/sql_select.h | 27 |
4 files changed, 59 insertions, 33 deletions
diff --git a/sql/opt_split.cc b/sql/opt_split.cc index 3ef8792d7bc..faec0f6e4d0 100644 --- a/sql/opt_split.cc +++ b/sql/opt_split.cc @@ -973,7 +973,7 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(double record_count, table_map all_table_map= (((table_map) 1) << join->table_count) - 1; reset_validity_vars_for_keyuses(best_key_keyuse_ext_start, best_table, best_key, remaining_tables, true); - choose_plan(join, all_table_map & ~join->const_table_map); + choose_plan(join, all_table_map & ~join->const_table_map, 0); /* Check that the chosen plan is really a splitting plan. diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index d40cb4e5159..712955e6911 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2484,8 +2484,7 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map) !sj_nest->sj_subq_pred->is_correlated && sj_nest->sj_subq_pred->types_allow_materialization) { - join->emb_sjm_nest= sj_nest; - if (choose_plan(join, all_table_map &~join->const_table_map)) + if (choose_plan(join, all_table_map &~join->const_table_map, sj_nest)) DBUG_RETURN(TRUE); /* purecov: inspected */ /* The best plan to run the subquery is now in join->best_positions, @@ -2578,7 +2577,6 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map) } } } - join->emb_sjm_nest= NULL; DBUG_RETURN(FALSE); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 67134d4c0c7..179ae33d00f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5952,7 +5952,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, /* Find an optimal join order of the non-constant tables. */ if (join->const_tables != join->table_count) { - if (choose_plan(join, all_table_map & ~join->const_table_map)) + if (choose_plan(join, all_table_map & ~join->const_table_map, 0)) goto error; #ifdef HAVE_valgrind @@ -9044,6 +9044,7 @@ static void choose_initial_table_order(JOIN *join) @param join pointer to the structure providing all context info for the query @param join_tables set of the tables in the query + @param emb_sjm_nest List of tables in case of materialized semi-join nest @retval FALSE ok @@ -9052,7 +9053,7 @@ static void choose_initial_table_order(JOIN *join) */ bool -choose_plan(JOIN *join, table_map join_tables) +choose_plan(JOIN *join, table_map join_tables, TABLE_LIST *emb_sjm_nest) { uint search_depth= join->thd->variables.optimizer_search_depth; uint prune_level= join->thd->variables.optimizer_prune_level; @@ -9060,18 +9061,25 @@ choose_plan(JOIN *join, table_map join_tables) join->thd->variables.optimizer_use_condition_selectivity; bool straight_join= MY_TEST(join->select_options & SELECT_STRAIGHT_JOIN); THD *thd= join->thd; + qsort2_cmp jtab_sort_func; DBUG_ENTER("choose_plan"); join->cur_embedding_map= 0; reset_nj_counters(join, join->join_list); - qsort2_cmp jtab_sort_func; - if (join->emb_sjm_nest) + if ((join->emb_sjm_nest= emb_sjm_nest)) { /* We're optimizing semi-join materialization nest, so put the tables from this semi-join as first */ jtab_sort_func= join_tab_cmp_embedded_first; + /* + If we are searching for the execution plan of a materialized semi-join + nest then allowed_tables contains bits only for the tables from this + nest. + */ + join->allowed_tables= (emb_sjm_nest->sj_inner_tables & + ~join->const_table_map); } else { @@ -9084,6 +9092,7 @@ choose_plan(JOIN *join, table_map join_tables) of records accessed. */ jtab_sort_func= straight_join ? join_tab_cmp_straight : join_tab_cmp; + join->allowed_tables= ~join->const_table_map; } /* @@ -9094,19 +9103,19 @@ choose_plan(JOIN *join, table_map join_tables) */ my_qsort2(join->best_ref + join->const_tables, join->table_count - join->const_tables, sizeof(JOIN_TAB*), - jtab_sort_func, (void*)join->emb_sjm_nest); + jtab_sort_func, (void*) emb_sjm_nest); Json_writer_object wrapper(thd); Json_writer_array trace_plan(thd,"considered_execution_plans"); - if (!join->emb_sjm_nest) - { + if (!emb_sjm_nest) choose_initial_table_order(join); - } + /* Note: constant tables are already in the join prefix. We don't put them into the cur_sj_inner_tables, though. */ + join->cur_sj_inner_tables= 0; if (straight_join) @@ -9132,6 +9141,8 @@ choose_plan(JOIN *join, table_map join_tables) */ if (join->thd->lex->is_single_level_stmt()) join->thd->status_var.last_query_cost= join->best_read; + + join->emb_sjm_nest= 0; DBUG_RETURN(FALSE); } @@ -9536,14 +9547,14 @@ greedy_search(JOIN *join, // ==join->tables or # tables in the sj-mat nest we're optimizing uint n_tables __attribute__((unused)); DBUG_ENTER("greedy_search"); + DBUG_ASSERT(!(remaining_tables & join->const_table_map)); /* number of tables that remain to be optimized */ n_tables= size_remain= my_count_bits(remaining_tables & - (join->emb_sjm_nest? - (join->emb_sjm_nest->sj_inner_tables & - ~join->const_table_map) - : - ~(table_map)0)); + (join->emb_sjm_nest ? + (join->emb_sjm_nest->sj_inner_tables & + ~join->const_table_map) : + ~(table_map)0)); do { /* Find the extension of the current QEP with the lowest cost */ @@ -10364,7 +10375,6 @@ best_extension_by_limited_search(JOIN *join, double best_read_time= DBL_MAX; bool disable_jbuf= join->thd->variables.join_cache_level == 0; enum_best_search best_res; - table_map allowed_tables= ~(table_map) 0; DBUG_ENTER("best_extension_by_limited_search"); DBUG_EXECUTE_IF("show_explain_probe_best_ext_lim_search", if (dbug_user_var_equals_int(thd, @@ -10379,22 +10389,15 @@ best_extension_by_limited_search(JOIN *join, DBUG_EXECUTE("opt", print_plan(join, idx, record_count, read_time, read_time, "part_plan");); - /* - If we are searching for the execution plan of a materialized semi-join nest - then allowed_tables contains bits only for the tables from this nest. - */ - if (join->emb_sjm_nest) - allowed_tables= (join->emb_sjm_nest->sj_inner_tables & - ~join->const_table_map); - for (pos= join->best_ref + idx ; (s= *pos) ; pos++) { table_map real_table_bit= s->table->map; DBUG_ASSERT(remaining_tables & real_table_bit); + DBUG_ASSERT(real_table_bit & ~join->const_table_map); swap_variables(JOIN_TAB*, join->best_ref[idx], *pos); - if ((allowed_tables & real_table_bit) && + if ((join->allowed_tables & real_table_bit) && !(remaining_tables & s->dependent) && !check_interleaving_with_nj(s)) { @@ -10463,7 +10466,7 @@ best_extension_by_limited_search(JOIN *join, */ if (best_record_count >= current_record_count && best_read_time >= current_read_time && - (!(position->key_dependent & allowed_tables) || + (!(position->key_dependent & join->allowed_tables) || position->records_read < 2.0)) { best_record_count= current_record_count; @@ -10501,7 +10504,7 @@ best_extension_by_limited_search(JOIN *join, .add("estimated_join_cardinality", partial_join_cardinality); if (search_depth > 1 && - ((remaining_tables & ~real_table_bit) & allowed_tables)) + ((remaining_tables & ~real_table_bit) & join->allowed_tables)) { /* Recursively expand the current partial plan */ @@ -17816,10 +17819,12 @@ static bool check_interleaving_with_nj(JOIN_TAB *next_tab) join->cur_embedding_map |= next_emb->nested_join->nj_map; } + DBUG_ASSERT(next_emb->nested_join->n_tables >= + next_emb->nested_join->counter); + if (next_emb->nested_join->n_tables != next_emb->nested_join->counter) break; - /* We're currently at Y or Z-bracket as depicted in the above picture. Mark that we've left it and continue walking up the brackets hierarchy. @@ -29267,7 +29272,7 @@ JOIN::reoptimize(Item *added_where, table_map join_tables, return REOPT_ERROR; /* Re-run the join optimizer to compute a new query plan. */ - if (choose_plan(this, join_tables)) + if (choose_plan(this, join_tables, 0)) return REOPT_ERROR; return REOPT_NEW_PLAN; diff --git a/sql/sql_select.h b/sql/sql_select.h index 8803b2a093e..3ee58ad8d14 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -359,7 +359,23 @@ typedef struct st_join_table { double cached_scan_time; double cached_scan_and_compare_time; - table_map dependent,key_dependent; + /* + dependent is the table that must be read before the current one + Used for example with STRAIGHT_JOIN or outer joins + */ + table_map dependent; + /* + key_dependent is dependent but add those tables that are used to compare + with a key field in a simple expression. See add_key_field(). + It is only used to prune searches in best_extension_by_limited_search() + */ + table_map key_dependent; + /* + Tables that have expression in their attached condition clause that depends + on this table. + */ + table_map related_tables; + /* Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra' column, or 0 if there is no info. @@ -1249,6 +1265,13 @@ public: bool hash_join; bool do_send_rows; table_map const_table_map; + + /* + Tables one is allowed to use in choose_plan(). Either all or + set to a mapt of the tables in the materialized semi-join nest + */ + table_map allowed_tables; + /** Bitmap of semijoin tables that the current partial plan decided to materialize and access by lookups @@ -2348,7 +2371,7 @@ inline Item * or_items(THD *thd, Item* cond, Item *item) { return (cond ? (new (thd->mem_root) Item_cond_or(thd, cond, item)) : item); } -bool choose_plan(JOIN *join, table_map join_tables); +bool choose_plan(JOIN *join, table_map join_tables, TABLE_LIST *emb_sjm_nest); void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab, table_map last_remaining_tables, bool first_alt, uint no_jbuf_before, |