mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
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
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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->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,
|
||||
@@ -2594,7 +2593,6 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
|
||||
}
|
||||
}
|
||||
}
|
||||
join->emb_sjm_nest= NULL;
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
|
||||
@@ -6035,7 +6035,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
|
||||
@@ -9238,6 +9238,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
|
||||
@@ -9246,13 +9247,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;
|
||||
@@ -9260,14 +9262,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
|
||||
{
|
||||
@@ -9280,6 +9288,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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -9290,19 +9299,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)
|
||||
@@ -9334,6 +9343,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);
|
||||
}
|
||||
|
||||
@@ -9728,6 +9739,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 ?
|
||||
@@ -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
|
||||
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.
|
||||
*/
|
||||
@@ -10880,7 +10891,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;
|
||||
@@ -10944,7 +10955,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 */
|
||||
@@ -18299,10 +18310,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.
|
||||
@@ -29869,7 +29882,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;
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user