mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
Merge branch '10.8' into 10.9
This commit is contained in:
@@ -111,12 +111,19 @@ static void optimize_straight_join(JOIN *join, table_map join_tables);
|
||||
static bool greedy_search(JOIN *join, table_map remaining_tables,
|
||||
uint depth, uint prune_level,
|
||||
uint use_cond_selectivity);
|
||||
static bool best_extension_by_limited_search(JOIN *join,
|
||||
table_map remaining_tables,
|
||||
uint idx, double record_count,
|
||||
double read_time, uint depth,
|
||||
uint prune_level,
|
||||
uint use_cond_selectivity);
|
||||
enum enum_best_search {
|
||||
SEARCH_ABORT= -2,
|
||||
SEARCH_ERROR= -1,
|
||||
SEARCH_OK= 0,
|
||||
SEARCH_FOUND_EDGE=1
|
||||
};
|
||||
static enum_best_search
|
||||
best_extension_by_limited_search(JOIN *join,
|
||||
table_map remaining_tables,
|
||||
uint idx, double record_count,
|
||||
double read_time, uint depth,
|
||||
uint prune_level,
|
||||
uint use_cond_selectivity);
|
||||
static uint determine_search_depth(JOIN* join);
|
||||
C_MODE_START
|
||||
static int join_tab_cmp(const void *dummy, const void* ptr1, const void* ptr2);
|
||||
@@ -409,6 +416,7 @@ POSITION::POSITION()
|
||||
range_rowid_filter_info= 0;
|
||||
ref_depend_map= dups_producing_tables= 0;
|
||||
inner_tables_handled_with_other_sjs= 0;
|
||||
type= JT_UNKNOWN;
|
||||
dups_weedout_picker.set_empty();
|
||||
firstmatch_picker.set_empty();
|
||||
loosescan_picker.set_empty();
|
||||
@@ -8468,6 +8476,7 @@ best_access_path(JOIN *join,
|
||||
pos->records_read= records;
|
||||
pos->read_time= best;
|
||||
pos->key= best_key;
|
||||
pos->type= best_type;
|
||||
pos->table= s;
|
||||
pos->ref_depend_map= best_ref_depends_map;
|
||||
pos->loosescan_picker.loosescan_key= MAX_KEY;
|
||||
@@ -9123,9 +9132,12 @@ greedy_search(JOIN *join,
|
||||
do {
|
||||
/* Find the extension of the current QEP with the lowest cost */
|
||||
join->best_read= DBL_MAX;
|
||||
if (best_extension_by_limited_search(join, remaining_tables, idx, record_count,
|
||||
read_time, search_depth, prune_level,
|
||||
use_cond_selectivity))
|
||||
if ((int) best_extension_by_limited_search(join, remaining_tables, idx,
|
||||
record_count,
|
||||
read_time, search_depth,
|
||||
prune_level,
|
||||
use_cond_selectivity) <
|
||||
(int) SEARCH_OK)
|
||||
DBUG_RETURN(TRUE);
|
||||
/*
|
||||
'best_read < DBL_MAX' means that optimizer managed to find
|
||||
@@ -9761,6 +9773,28 @@ exit:
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Check if the table is an EQ_REF or similar table and there is no cost
|
||||
to gain by moveing it to a later stage.
|
||||
We call such a table a edge table (or hanging leaf) as it will read at
|
||||
most one row and will not add to the number of row combinations in the join.
|
||||
*/
|
||||
|
||||
static inline enum_best_search
|
||||
check_if_edge_table(POSITION *pos,
|
||||
double pushdown_cond_selectivity)
|
||||
{
|
||||
|
||||
if ((pos->type == JT_EQ_REF ||
|
||||
(pos->type == JT_REF &&
|
||||
pos->records_read == 1 &&
|
||||
!pos->range_rowid_filter_info)) &&
|
||||
pushdown_cond_selectivity >= 0.999)
|
||||
return SEARCH_FOUND_EDGE;
|
||||
return SEARCH_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Find a good, possibly optimal, query execution plan (QEP) by a possibly
|
||||
exhaustive search.
|
||||
@@ -9875,12 +9909,17 @@ exit:
|
||||
pushed to a table should be taken into account
|
||||
|
||||
@retval
|
||||
FALSE ok
|
||||
enum_best_search::SEARCH_OK All fine
|
||||
@retval
|
||||
TRUE Fatal error
|
||||
enum_best_search::SEARCH_FOUND_EDGE All remaning tables are edge tables
|
||||
@retval
|
||||
enum_best_search::SEARCH_ABORT Killed by user
|
||||
@retval
|
||||
enum_best_search::SEARCH_ERROR Fatal error
|
||||
*/
|
||||
|
||||
static bool
|
||||
|
||||
static enum_best_search
|
||||
best_extension_by_limited_search(JOIN *join,
|
||||
table_map remaining_tables,
|
||||
uint idx,
|
||||
@@ -9890,9 +9929,17 @@ best_extension_by_limited_search(JOIN *join,
|
||||
uint prune_level,
|
||||
uint use_cond_selectivity)
|
||||
{
|
||||
DBUG_ENTER("best_extension_by_limited_search");
|
||||
|
||||
THD *thd= join->thd;
|
||||
/*
|
||||
'join' is a partial plan with lower cost than the best plan so far,
|
||||
so continue expanding it further with the tables in 'remaining_tables'.
|
||||
*/
|
||||
JOIN_TAB *s;
|
||||
double best_record_count= DBL_MAX;
|
||||
double best_read_time= DBL_MAX;
|
||||
bool disable_jbuf= join->thd->variables.join_cache_level == 0;
|
||||
enum_best_search best_res;
|
||||
DBUG_ENTER("best_extension_by_limited_search");
|
||||
|
||||
DBUG_EXECUTE_IF("show_explain_probe_best_ext_lim_search",
|
||||
if (dbug_user_var_equals_int(thd,
|
||||
@@ -9902,19 +9949,7 @@ best_extension_by_limited_search(JOIN *join,
|
||||
);
|
||||
|
||||
if (unlikely(thd->check_killed())) // Abort
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
DBUG_EXECUTE("opt", print_plan(join, idx, read_time, record_count, idx,
|
||||
"SOFAR:"););
|
||||
|
||||
/*
|
||||
'join' is a partial plan with lower cost than the best plan so far,
|
||||
so continue expanding it further with the tables in 'remaining_tables'.
|
||||
*/
|
||||
JOIN_TAB *s;
|
||||
double best_record_count= DBL_MAX;
|
||||
double best_read_time= DBL_MAX;
|
||||
bool disable_jbuf= join->thd->variables.join_cache_level == 0;
|
||||
DBUG_RETURN(SEARCH_ABORT);
|
||||
|
||||
DBUG_EXECUTE("opt", print_plan(join, idx, record_count, read_time, read_time,
|
||||
"part_plan"););
|
||||
@@ -9930,15 +9965,18 @@ best_extension_by_limited_search(JOIN *join,
|
||||
for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
|
||||
{
|
||||
table_map real_table_bit= s->table->map;
|
||||
if ((remaining_tables & real_table_bit) &&
|
||||
(allowed_tables & real_table_bit) &&
|
||||
DBUG_ASSERT(remaining_tables & real_table_bit);
|
||||
|
||||
if ((allowed_tables & real_table_bit) &&
|
||||
!(remaining_tables & s->dependent) &&
|
||||
(!idx || !check_interleaving_with_nj(s)))
|
||||
!check_interleaving_with_nj(s))
|
||||
{
|
||||
double current_record_count, current_read_time;
|
||||
double partial_join_cardinality;
|
||||
POSITION *position= join->positions + idx;
|
||||
|
||||
POSITION loose_scan_pos;
|
||||
Json_writer_object trace_one_table(thd);
|
||||
|
||||
if (unlikely(thd->trace_started()))
|
||||
{
|
||||
trace_plan_prefix(join, idx, remaining_tables);
|
||||
@@ -9946,7 +9984,6 @@ best_extension_by_limited_search(JOIN *join,
|
||||
}
|
||||
|
||||
/* Find the best access method from 's' to the current partial plan */
|
||||
POSITION loose_scan_pos;
|
||||
best_access_path(join, s, remaining_tables, join->positions, idx,
|
||||
disable_jbuf, record_count, position, &loose_scan_pos);
|
||||
|
||||
@@ -10021,32 +10058,51 @@ best_extension_by_limited_search(JOIN *join,
|
||||
double pushdown_cond_selectivity= 1.0;
|
||||
if (use_cond_selectivity > 1)
|
||||
pushdown_cond_selectivity= table_cond_selectivity(join, idx, s,
|
||||
remaining_tables &
|
||||
remaining_tables &
|
||||
~real_table_bit);
|
||||
join->positions[idx].cond_selectivity= pushdown_cond_selectivity;
|
||||
|
||||
if (unlikely(thd->trace_started()) && pushdown_cond_selectivity < 1.0)
|
||||
trace_one_table.add("selectivity", pushdown_cond_selectivity);
|
||||
partial_join_cardinality= (current_record_count *
|
||||
pushdown_cond_selectivity);
|
||||
|
||||
double partial_join_cardinality= current_record_count *
|
||||
pushdown_cond_selectivity;
|
||||
if ( (search_depth > 1) && (remaining_tables & ~real_table_bit) & allowed_tables )
|
||||
{ /* Recursively expand the current partial plan */
|
||||
if (unlikely(thd->trace_started()))
|
||||
{
|
||||
if (pushdown_cond_selectivity < 1.0)
|
||||
{
|
||||
trace_one_table.add("selectivity", pushdown_cond_selectivity);
|
||||
trace_one_table.add("estimated_join_cardinality",
|
||||
partial_join_cardinality);
|
||||
}
|
||||
}
|
||||
|
||||
if ((search_depth > 1) && (remaining_tables & ~real_table_bit) &
|
||||
allowed_tables)
|
||||
{
|
||||
/* Recursively expand the current partial plan */
|
||||
swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
|
||||
Json_writer_array trace_rest(thd, "rest_of_plan");
|
||||
if (best_extension_by_limited_search(join,
|
||||
remaining_tables & ~real_table_bit,
|
||||
idx + 1,
|
||||
partial_join_cardinality,
|
||||
current_read_time,
|
||||
search_depth - 1,
|
||||
prune_level,
|
||||
use_cond_selectivity))
|
||||
DBUG_RETURN(TRUE);
|
||||
best_res=
|
||||
best_extension_by_limited_search(join,
|
||||
remaining_tables &
|
||||
~real_table_bit,
|
||||
idx + 1,
|
||||
partial_join_cardinality,
|
||||
current_read_time,
|
||||
search_depth - 1,
|
||||
prune_level,
|
||||
use_cond_selectivity);
|
||||
if ((int) best_res < (int) SEARCH_OK)
|
||||
DBUG_RETURN(best_res); // Abort
|
||||
swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
|
||||
if (best_res == SEARCH_FOUND_EDGE &&
|
||||
check_if_edge_table(join->positions+ idx,
|
||||
pushdown_cond_selectivity) !=
|
||||
SEARCH_FOUND_EDGE)
|
||||
best_res= SEARCH_OK;
|
||||
}
|
||||
else
|
||||
{ /*
|
||||
{
|
||||
/*
|
||||
'join' is either the best partial QEP with 'search_depth' relations,
|
||||
or the best complete QEP so far, whichever is smaller.
|
||||
*/
|
||||
@@ -10055,15 +10111,13 @@ best_extension_by_limited_search(JOIN *join,
|
||||
join->positions[join->const_tables].table->table)
|
||||
{
|
||||
/*
|
||||
We may have to make a temp table, note that this is only a
|
||||
heuristic since we cannot know for sure at this point.
|
||||
Hence it may be wrong.
|
||||
We may have to make a temp table, note that this is only a
|
||||
heuristic since we cannot know for sure at this point.
|
||||
Hence it may be wrong.
|
||||
*/
|
||||
trace_one_table.add("cost_for_sorting", current_record_count);
|
||||
current_read_time= COST_ADD(current_read_time, current_record_count);
|
||||
}
|
||||
trace_one_table.add("estimated_join_cardinality",
|
||||
partial_join_cardinality);
|
||||
if (current_read_time < join->best_read)
|
||||
{
|
||||
memcpy((uchar*) join->best_positions, (uchar*) join->positions,
|
||||
@@ -10076,12 +10130,19 @@ best_extension_by_limited_search(JOIN *join,
|
||||
read_time,
|
||||
current_read_time,
|
||||
"full_plan"););
|
||||
best_res= check_if_edge_table(join->positions + idx,
|
||||
pushdown_cond_selectivity);
|
||||
}
|
||||
restore_prev_nj_state(s);
|
||||
restore_prev_sj_state(remaining_tables, s, idx);
|
||||
if (best_res == SEARCH_FOUND_EDGE)
|
||||
{
|
||||
trace_one_table.add("pruned_by_hanging_leaf", true);
|
||||
DBUG_RETURN(best_res);
|
||||
}
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(FALSE);
|
||||
DBUG_RETURN(SEARCH_OK);
|
||||
}
|
||||
|
||||
|
||||
@@ -17233,7 +17294,6 @@ static uint reset_nj_counters(JOIN *join, List<TABLE_LIST> *join_list)
|
||||
|
||||
static bool check_interleaving_with_nj(JOIN_TAB *next_tab)
|
||||
{
|
||||
TABLE_LIST *next_emb= next_tab->table->pos_in_table_list->embedding;
|
||||
JOIN *join= next_tab->join;
|
||||
|
||||
if (join->cur_embedding_map & ~next_tab->embedding_map)
|
||||
@@ -17245,6 +17305,7 @@ static bool check_interleaving_with_nj(JOIN_TAB *next_tab)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
TABLE_LIST *next_emb= next_tab->table->pos_in_table_list->embedding;
|
||||
/*
|
||||
Do update counters for "pairs of brackets" that we've left (marked as
|
||||
X,Y,Z in the above picture)
|
||||
@@ -18430,14 +18491,17 @@ Field *Item_default_value::create_tmp_field_ex(MEM_ROOT *root, TABLE *table,
|
||||
Tmp_field_src *src,
|
||||
const Tmp_field_param *param)
|
||||
{
|
||||
if (field->default_value && (field->flags & BLOB_FLAG))
|
||||
if (field->default_value || (field->flags & BLOB_FLAG))
|
||||
{
|
||||
/*
|
||||
We have to use a copy function when using a blob with default value
|
||||
as the we have to calculate the default value before we can use it.
|
||||
*/
|
||||
get_tmp_field_src(src, param);
|
||||
return tmp_table_field_from_field_type(root, table);
|
||||
Field *result= tmp_table_field_from_field_type(root, table);
|
||||
if (result && param->modify_item())
|
||||
result_field= result;
|
||||
return result;
|
||||
}
|
||||
/*
|
||||
Same code as in Item_field::create_tmp_field_ex, except no default field
|
||||
@@ -18874,6 +18938,7 @@ TABLE *Create_tmp_table::start(THD *thd,
|
||||
table->copy_blobs= 1;
|
||||
table->in_use= thd;
|
||||
table->no_rows_with_nulls= param->force_not_null_cols;
|
||||
table->expr_arena= thd;
|
||||
|
||||
table->s= share;
|
||||
init_tmp_table_share(thd, share, "", 0, "(temporary)", tmpname);
|
||||
@@ -25087,8 +25152,8 @@ int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
|
||||
if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
|
||||
all_fields, false, true, from_window_spec))
|
||||
return 1;
|
||||
if ((*order->item)->with_window_func() &&
|
||||
context_analysis_place != IN_ORDER_BY)
|
||||
Item * const item= *order->item;
|
||||
if (item->with_window_func() && context_analysis_place != IN_ORDER_BY)
|
||||
{
|
||||
my_error(ER_WINDOW_FUNCTION_IN_WINDOW_SPEC, MYF(0));
|
||||
return 1;
|
||||
@@ -25099,20 +25164,18 @@ int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
|
||||
an ORDER BY clause
|
||||
*/
|
||||
|
||||
if (for_union &&
|
||||
((*order->item)->with_sum_func() ||
|
||||
(*order->item)->with_window_func()))
|
||||
if (for_union && (item->with_sum_func() || item->with_window_func()))
|
||||
{
|
||||
my_error(ER_AGGREGATE_ORDER_FOR_UNION, MYF(0), number);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(*order->item)->with_sum_func())
|
||||
continue;
|
||||
|
||||
if (from_window_spec && (*order->item)->type() != Item::SUM_FUNC_ITEM)
|
||||
(*order->item)->split_sum_func(thd, ref_pointer_array,
|
||||
all_fields, SPLIT_SUM_SELECT);
|
||||
if ((from_window_spec && item->with_sum_func() &&
|
||||
item->type() != Item::SUM_FUNC_ITEM) || item->with_window_func())
|
||||
{
|
||||
item->split_sum_func(thd, ref_pointer_array,
|
||||
all_fields, SPLIT_SUM_SELECT);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -26062,15 +26125,17 @@ change_to_use_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array,
|
||||
for (uint i= 0; (item= it++); i++)
|
||||
{
|
||||
Field *field;
|
||||
if ((item->with_sum_func() && item->type() != Item::SUM_FUNC_ITEM) ||
|
||||
item->with_window_func())
|
||||
enum Item::Type item_type= item->type();
|
||||
if ((item->with_sum_func() && item_type != Item::SUM_FUNC_ITEM) ||
|
||||
item->with_window_func())
|
||||
item_field= item;
|
||||
else if (item->type() == Item::FIELD_ITEM)
|
||||
else if (item_type == Item::FIELD_ITEM ||
|
||||
item_type == Item::DEFAULT_VALUE_ITEM)
|
||||
{
|
||||
if (!(item_field= item->get_tmp_table_item(thd)))
|
||||
DBUG_RETURN(true);
|
||||
}
|
||||
else if (item->type() == Item::FUNC_ITEM &&
|
||||
else if (item_type == Item::FUNC_ITEM &&
|
||||
((Item_func*)item)->functype() == Item_func::SUSERVAR_FUNC)
|
||||
{
|
||||
field= item->get_tmp_table_field();
|
||||
@@ -27929,7 +27994,7 @@ static void print_table_array(THD *thd,
|
||||
too)
|
||||
*/
|
||||
|
||||
static bool is_eliminated_table(table_map eliminated_tables, TABLE_LIST *tbl)
|
||||
bool is_eliminated_table(table_map eliminated_tables, TABLE_LIST *tbl)
|
||||
{
|
||||
return eliminated_tables &&
|
||||
((tbl->table && (tbl->table->map & eliminated_tables)) ||
|
||||
|
Reference in New Issue
Block a user