Commit 1d82e5da authored by Monty's avatar Monty Committed by Sergei Petrunia

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
parent 249475b9
...@@ -973,7 +973,7 @@ SplM_plan_info * JOIN_TAB::choose_best_splitting(double record_count, ...@@ -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; table_map all_table_map= (((table_map) 1) << join->table_count) - 1;
reset_validity_vars_for_keyuses(best_key_keyuse_ext_start, best_table, reset_validity_vars_for_keyuses(best_key_keyuse_ext_start, best_table,
best_key, remaining_tables, true); 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. Check that the chosen plan is really a splitting plan.
......
...@@ -2500,8 +2500,7 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map) ...@@ -2500,8 +2500,7 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
!sj_nest->sj_subq_pred->is_correlated && !sj_nest->sj_subq_pred->is_correlated &&
sj_nest->sj_subq_pred->types_allow_materialization) 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, sj_nest))
if (choose_plan(join, all_table_map &~join->const_table_map))
DBUG_RETURN(TRUE); /* purecov: inspected */ DBUG_RETURN(TRUE); /* purecov: inspected */
/* /*
The best plan to run the subquery is now in join->best_positions, The best plan to run the subquery is now in join->best_positions,
...@@ -2594,7 +2593,6 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map) ...@@ -2594,7 +2593,6 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
} }
} }
} }
join->emb_sjm_nest= NULL;
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
......
...@@ -6035,7 +6035,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, ...@@ -6035,7 +6035,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
/* Find an optimal join order of the non-constant tables. */ /* Find an optimal join order of the non-constant tables. */
if (join->const_tables != join->table_count) 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; goto error;
#ifdef HAVE_valgrind #ifdef HAVE_valgrind
...@@ -9238,6 +9238,7 @@ static void choose_initial_table_order(JOIN *join) ...@@ -9238,6 +9238,7 @@ static void choose_initial_table_order(JOIN *join)
@param join pointer to the structure providing all context info for @param join pointer to the structure providing all context info for
the query the query
@param join_tables set of the tables in 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 @retval
FALSE ok FALSE ok
...@@ -9246,13 +9247,14 @@ static void choose_initial_table_order(JOIN *join) ...@@ -9246,13 +9247,14 @@ static void choose_initial_table_order(JOIN *join)
*/ */
bool 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 search_depth= join->thd->variables.optimizer_search_depth;
uint use_cond_selectivity= uint use_cond_selectivity=
join->thd->variables.optimizer_use_condition_selectivity; join->thd->variables.optimizer_use_condition_selectivity;
bool straight_join= MY_TEST(join->select_options & SELECT_STRAIGHT_JOIN); bool straight_join= MY_TEST(join->select_options & SELECT_STRAIGHT_JOIN);
THD *thd= join->thd; THD *thd= join->thd;
qsort2_cmp jtab_sort_func;
DBUG_ENTER("choose_plan"); DBUG_ENTER("choose_plan");
join->cur_embedding_map= 0; join->cur_embedding_map= 0;
...@@ -9260,14 +9262,20 @@ choose_plan(JOIN *join, table_map join_tables) ...@@ -9260,14 +9262,20 @@ choose_plan(JOIN *join, table_map join_tables)
join->prune_level= join->thd->variables.optimizer_prune_level; join->prune_level= join->thd->variables.optimizer_prune_level;
reset_nj_counters(join, join->join_list); 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 /* We're optimizing semi-join materialization nest, so put the
tables from this semi-join as first tables from this semi-join as first
*/ */
jtab_sort_func= join_tab_cmp_embedded_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 else
{ {
...@@ -9280,6 +9288,7 @@ choose_plan(JOIN *join, table_map join_tables) ...@@ -9280,6 +9288,7 @@ choose_plan(JOIN *join, table_map join_tables)
of records accessed. of records accessed.
*/ */
jtab_sort_func= straight_join ? join_tab_cmp_straight : join_tab_cmp; jtab_sort_func= straight_join ? join_tab_cmp_straight : join_tab_cmp;
join->allowed_tables= ~join->const_table_map;
} }
/* /*
...@@ -9290,19 +9299,19 @@ choose_plan(JOIN *join, table_map join_tables) ...@@ -9290,19 +9299,19 @@ choose_plan(JOIN *join, table_map join_tables)
*/ */
my_qsort2(join->best_ref + join->const_tables, my_qsort2(join->best_ref + join->const_tables,
join->table_count - join->const_tables, sizeof(JOIN_TAB*), 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_object wrapper(thd);
Json_writer_array trace_plan(thd,"considered_execution_plans"); Json_writer_array trace_plan(thd,"considered_execution_plans");
if (!join->emb_sjm_nest) if (!emb_sjm_nest)
{
choose_initial_table_order(join); choose_initial_table_order(join);
}
/* /*
Note: constant tables are already in the join prefix. We don't Note: constant tables are already in the join prefix. We don't
put them into the cur_sj_inner_tables, though. put them into the cur_sj_inner_tables, though.
*/ */
join->cur_sj_inner_tables= 0; join->cur_sj_inner_tables= 0;
if (straight_join) if (straight_join)
...@@ -9334,6 +9343,8 @@ choose_plan(JOIN *join, table_map join_tables) ...@@ -9334,6 +9343,8 @@ choose_plan(JOIN *join, table_map join_tables)
*/ */
if (join->thd->lex->is_single_level_stmt()) if (join->thd->lex->is_single_level_stmt())
join->thd->status_var.last_query_cost= join->best_read; join->thd->status_var.last_query_cost= join->best_read;
join->emb_sjm_nest= 0;
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
...@@ -9728,6 +9739,7 @@ greedy_search(JOIN *join, ...@@ -9728,6 +9739,7 @@ greedy_search(JOIN *join,
// ==join->tables or # tables in the sj-mat nest we're optimizing // ==join->tables or # tables in the sj-mat nest we're optimizing
uint n_tables __attribute__((unused)); uint n_tables __attribute__((unused));
DBUG_ENTER("greedy_search"); DBUG_ENTER("greedy_search");
DBUG_ASSERT(!(remaining_tables & join->const_table_map));
/* number of tables that remain to be optimized */ /* number of tables that remain to be optimized */
usable_tables= (join->emb_sjm_nest ? usable_tables= (join->emb_sjm_nest ?
...@@ -10716,7 +10728,6 @@ best_extension_by_limited_search(JOIN *join, ...@@ -10716,7 +10728,6 @@ best_extension_by_limited_search(JOIN *join,
/* /*
allowed_tables is used to check if there are tables left that can improve 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. 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 allowed_current_tables tells us which tables we can add to the current
plan at this stage. plan at this stage.
*/ */
...@@ -10880,7 +10891,7 @@ best_extension_by_limited_search(JOIN *join, ...@@ -10880,7 +10891,7 @@ best_extension_by_limited_search(JOIN *join,
*/ */
if (best_record_count >= current_record_count && if (best_record_count >= current_record_count &&
best_read_time >= current_read_time && best_read_time >= current_read_time &&
(!(position->key_dependent & allowed_tables) || (!(position->key_dependent & join->allowed_tables) ||
position->records_read < 2.0)) position->records_read < 2.0))
{ {
best_record_count= current_record_count; best_record_count= current_record_count;
...@@ -10944,7 +10955,7 @@ best_extension_by_limited_search(JOIN *join, ...@@ -10944,7 +10955,7 @@ best_extension_by_limited_search(JOIN *join,
.add("estimated_join_cardinality", partial_join_cardinality); .add("estimated_join_cardinality", partial_join_cardinality);
if (search_depth > 1 && 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 */ /* Recursively expand the current partial plan */
...@@ -18299,10 +18310,12 @@ static bool check_interleaving_with_nj(JOIN_TAB *next_tab) ...@@ -18299,10 +18310,12 @@ static bool check_interleaving_with_nj(JOIN_TAB *next_tab)
join->cur_embedding_map |= next_emb->nested_join->nj_map; 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 != if (next_emb->nested_join->n_tables !=
next_emb->nested_join->counter) next_emb->nested_join->counter)
break; break;
/* /*
We're currently at Y or Z-bracket as depicted in the above picture. 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. Mark that we've left it and continue walking up the brackets hierarchy.
...@@ -29869,7 +29882,7 @@ JOIN::reoptimize(Item *added_where, table_map join_tables, ...@@ -29869,7 +29882,7 @@ JOIN::reoptimize(Item *added_where, table_map join_tables,
return REOPT_ERROR; return REOPT_ERROR;
/* Re-run the join optimizer to compute a new query plan. */ /* 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_ERROR;
return REOPT_NEW_PLAN; return REOPT_NEW_PLAN;
...@@ -359,7 +359,23 @@ typedef struct st_join_table { ...@@ -359,7 +359,23 @@ typedef struct st_join_table {
double cached_scan_time; double cached_scan_time;
double cached_scan_and_compare_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' Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
column, or 0 if there is no info. column, or 0 if there is no info.
...@@ -1256,6 +1272,13 @@ class JOIN :public Sql_alloc ...@@ -1256,6 +1272,13 @@ class JOIN :public Sql_alloc
bool hash_join; bool hash_join;
bool do_send_rows; bool do_send_rows;
table_map const_table_map; 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 Bitmap of semijoin tables that the current partial plan decided
to materialize and access by lookups to materialize and access by lookups
...@@ -2370,7 +2393,7 @@ inline Item * or_items(THD *thd, Item* cond, Item *item) ...@@ -2370,7 +2393,7 @@ inline Item * or_items(THD *thd, Item* cond, Item *item)
{ {
return (cond ? (new (thd->mem_root) Item_cond_or(thd, 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, void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab,
table_map last_remaining_tables, table_map last_remaining_tables,
bool first_alt, uint no_jbuf_before, bool first_alt, uint no_jbuf_before,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment