diff options
author | Monty <monty@mariadb.org> | 2022-06-13 17:45:37 +0300 |
---|---|---|
committer | Monty <monty@mariadb.org> | 2022-11-16 15:48:54 +0200 |
commit | c2b4c49fc4ec7e428ce6f6a26849f29d00e6e99d (patch) | |
tree | 8297fc17c63fb6b33d8a02e3ecf8d0d7f53e5487 | |
parent | a68b8fbe48db1ceb288effc8d8541728bdf83c93 (diff) | |
download | mariadb-git-c2b4c49fc4ec7e428ce6f6a26849f29d00e6e99d.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 | 39 | ||||
-rw-r--r-- | sql/sql_select.h | 27 |
4 files changed, 53 insertions, 19 deletions
diff --git a/sql/opt_split.cc b/sql/opt_split.cc index 1bd90869f2e..6c31b895378 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 78bcb12066b..b29a28d70b6 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2485,8 +2485,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, @@ -2579,7 +2578,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 81832f727d5..787e256c91b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6025,7 +6025,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 @@ -9181,6 +9181,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 @@ -9189,13 +9190,14 @@ 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 use_cond_selectivity= 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; @@ -9203,14 +9205,20 @@ choose_plan(JOIN *join, table_map join_tables) join->prune_level= join->thd->variables.optimizer_prune_level; 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 { @@ -9223,6 +9231,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; } /* @@ -9233,19 +9242,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) @@ -9277,6 +9286,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); } @@ -9671,6 +9682,7 @@ 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 */ usable_tables= (join->emb_sjm_nest ? @@ -10659,7 +10671,6 @@ best_extension_by_limited_search(JOIN *join, /* allowed_tables is used to check if there are tables left that can improve a key search and to see if there are more tables to add in next iteration. - allowed_current_tables tells us which tables we can add to the current plan at this stage. */ @@ -10823,7 +10834,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; @@ -10887,7 +10898,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 */ @@ -18214,10 +18225,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. @@ -29784,7 +29797,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 25257e6b917..9bf0c83186e 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. @@ -1256,6 +1272,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 @@ -2371,7 +2394,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, |