summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2022-06-13 17:45:37 +0300
committerMonty <monty@mariadb.org>2022-11-16 15:48:54 +0200
commitc2b4c49fc4ec7e428ce6f6a26849f29d00e6e99d (patch)
tree8297fc17c63fb6b33d8a02e3ecf8d0d7f53e5487
parenta68b8fbe48db1ceb288effc8d8541728bdf83c93 (diff)
downloadmariadb-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.cc2
-rw-r--r--sql/opt_subselect.cc4
-rw-r--r--sql/sql_select.cc39
-rw-r--r--sql/sql_select.h27
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,