Commit fdb77fd3 authored by Varun Gupta's avatar Varun Gupta

Fix to address performance regression of ORDER BY with limit queries

parent 5a9e6261
...@@ -3140,7 +3140,7 @@ bool Sj_materialization_picker::check_qep(JOIN *join, ...@@ -3140,7 +3140,7 @@ bool Sj_materialization_picker::check_qep(JOIN *join,
best_access_path(join, join->positions[i].table, rem_tables, best_access_path(join, join->positions[i].table, rem_tables,
join->positions, i, join->positions, i,
disable_jbuf, prefix_rec_count, &curpos, &dummy, disable_jbuf, prefix_rec_count, &curpos, &dummy,
0, FALSE); 0, FALSE, DBL_MAX);
prefix_rec_count= COST_MULT(prefix_rec_count, curpos.records_read); prefix_rec_count= COST_MULT(prefix_rec_count, curpos.records_read);
prefix_cost= COST_ADD(prefix_cost, curpos.read_time); prefix_cost= COST_ADD(prefix_cost, curpos.read_time);
prefix_cost= COST_ADD(prefix_cost, prefix_cost= COST_ADD(prefix_cost,
...@@ -3839,7 +3839,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join) ...@@ -3839,7 +3839,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
best_access_path(join, join->best_positions[i].table, rem_tables, best_access_path(join, join->best_positions[i].table, rem_tables,
join->best_positions, i, join->best_positions, i,
FALSE, prefix_rec_count, FALSE, prefix_rec_count,
join->best_positions + i, &dummy, 0, FALSE); join->best_positions + i, &dummy, 0, FALSE, DBL_MAX);
join->best_positions[i].sort_nest_operation_here= save_sort_nest_op; join->best_positions[i].sort_nest_operation_here= save_sort_nest_op;
prefix_rec_count *= join->best_positions[i].records_read; prefix_rec_count *= join->best_positions[i].records_read;
rem_tables &= ~join->best_positions[i].table->table->map; rem_tables &= ~join->best_positions[i].table->table->map;
...@@ -3882,7 +3882,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join) ...@@ -3882,7 +3882,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
rem_tables, join->best_positions, idx, rem_tables, join->best_positions, idx,
TRUE /* no jbuf */, TRUE /* no jbuf */,
record_count, join->best_positions + idx, &dummy, record_count, join->best_positions + idx, &dummy,
0, FALSE); 0, FALSE, DBL_MAX);
} }
record_count *= join->best_positions[idx].records_read; record_count *= join->best_positions[idx].records_read;
rem_tables &= ~join->best_positions[idx].table->table->map; rem_tables &= ~join->best_positions[idx].table->table->map;
...@@ -3922,7 +3922,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join) ...@@ -3922,7 +3922,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
rem_tables, join->best_positions, idx, rem_tables, join->best_positions, idx,
TRUE /* no jbuf */, TRUE /* no jbuf */,
record_count, join->best_positions + idx, record_count, join->best_positions + idx,
&loose_scan_pos, 0, FALSE); &loose_scan_pos, 0, FALSE, DBL_MAX);
if (idx==first) if (idx==first)
{ {
join->best_positions[idx]= loose_scan_pos; join->best_positions[idx]= loose_scan_pos;
......
...@@ -119,7 +119,8 @@ static bool best_extension_by_limited_search(JOIN *join, ...@@ -119,7 +119,8 @@ static bool best_extension_by_limited_search(JOIN *join,
uint use_cond_selectivity, uint use_cond_selectivity,
table_map sort_nest_tables, table_map sort_nest_tables,
bool nest_created, bool nest_created,
bool limit_applied_to_nest); bool limit_applied_to_nest,
double sort_nest_records);
static uint determine_search_depth(JOIN* join); static uint determine_search_depth(JOIN* join);
C_MODE_START C_MODE_START
static int join_tab_cmp(const void *dummy, const void* ptr1, const void* ptr2); static int join_tab_cmp(const void *dummy, const void* ptr1, const void* ptr2);
...@@ -7294,7 +7295,8 @@ best_access_path(JOIN *join, ...@@ -7294,7 +7295,8 @@ best_access_path(JOIN *join,
double record_count, double record_count,
POSITION *pos, POSITION *pos,
POSITION *loose_scan_pos, POSITION *loose_scan_pos,
table_map sort_nest_tables, bool nest_created) table_map sort_nest_tables, bool nest_created,
double sort_nest_records)
{ {
THD *thd= join->thd; THD *thd= join->thd;
uint use_cond_selectivity= thd->variables.optimizer_use_condition_selectivity; uint use_cond_selectivity= thd->variables.optimizer_use_condition_selectivity;
...@@ -7415,9 +7417,9 @@ best_access_path(JOIN *join, ...@@ -7415,9 +7417,9 @@ best_access_path(JOIN *join,
double tmp2= prev_record_reads(join_positions, idx, double tmp2= prev_record_reads(join_positions, idx,
(found_ref | keyuse->used_tables), (found_ref | keyuse->used_tables),
sort_nest_tables, sort_nest_tables,
nest_created ? nest_created,
join->fraction_output_for_nest : nest_created ? sort_nest_records:
1.0); DBL_MAX);
if (tmp2 < best_prev_record_reads) if (tmp2 < best_prev_record_reads)
{ {
best_part_found_ref= keyuse->used_tables & ~join->const_table_map; best_part_found_ref= keyuse->used_tables & ~join->const_table_map;
...@@ -7459,9 +7461,8 @@ best_access_path(JOIN *join, ...@@ -7459,9 +7461,8 @@ best_access_path(JOIN *join,
but 1.0 would be probably safer but 1.0 would be probably safer
*/ */
tmp= prev_record_reads(join_positions, idx, found_ref, tmp= prev_record_reads(join_positions, idx, found_ref,
sort_nest_tables, sort_nest_tables, nest_created,
nest_created ? nest_created ? sort_nest_records : DBL_MAX);
join->fraction_output_for_nest : 1.0);
records= 1.0; records= 1.0;
type= JT_FT; type= JT_FT;
trace_access_idx.add("access_type", join_type_str[type]) trace_access_idx.add("access_type", join_type_str[type])
...@@ -7491,9 +7492,9 @@ best_access_path(JOIN *join, ...@@ -7491,9 +7492,9 @@ best_access_path(JOIN *join,
trace_access_idx.add("access_type", join_type_str[type]) trace_access_idx.add("access_type", join_type_str[type])
.add("index", keyinfo->name); .add("index", keyinfo->name);
tmp = prev_record_reads(join_positions, idx, found_ref, tmp = prev_record_reads(join_positions, idx, found_ref,
sort_nest_tables, sort_nest_tables, nest_created,
nest_created ? nest_created ?
join->fraction_output_for_nest : 1.0); sort_nest_records : DBL_MAX);
records=1.0; records=1.0;
} }
else else
...@@ -8147,7 +8148,6 @@ best_access_path(JOIN *join, ...@@ -8147,7 +8148,6 @@ best_access_path(JOIN *join,
join->sort_by_table= (TABLE*) 1; // Must use temporary table join->sort_by_table= (TABLE*) 1; // Must use temporary table
} }
trace_access_scan.end(); trace_access_scan.end();
trace_paths.end();
/* /*
Use the estimate of rows read for a table for range/table scan Use the estimate of rows read for a table for range/table scan
...@@ -8222,6 +8222,8 @@ best_access_path(JOIN *join, ...@@ -8222,6 +8222,8 @@ best_access_path(JOIN *join,
if (unlikely(thd->trace_started())) if (unlikely(thd->trace_started()))
print_best_access_for_table(thd, pos, best_type); print_best_access_for_table(thd, pos, best_type);
trace_paths.end();
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -8717,7 +8719,7 @@ optimize_straight_join(JOIN *join, table_map join_tables) ...@@ -8717,7 +8719,7 @@ optimize_straight_join(JOIN *join, table_map join_tables)
best_access_path(join, s, join_tables, join->positions, idx, best_access_path(join, s, join_tables, join->positions, idx,
disable_jbuf, record_count, disable_jbuf, record_count,
position, &loose_scan_pos, position, &loose_scan_pos,
0, FALSE); 0, FALSE, DBL_MAX);
/* compute the cost of the new plan extended with 's' */ /* compute the cost of the new plan extended with 's' */
record_count= COST_MULT(record_count, position->records_read); record_count= COST_MULT(record_count, position->records_read);
...@@ -8873,7 +8875,7 @@ greedy_search(JOIN *join, ...@@ -8873,7 +8875,7 @@ greedy_search(JOIN *join,
prune_level), prune_level),
use_cond_selectivity, use_cond_selectivity,
sort_nest_tables, FALSE, sort_nest_tables, FALSE,
FALSE)) FALSE, DBL_MAX))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
/* /*
'best_read < DBL_MAX' means that optimizer managed to find 'best_read < DBL_MAX' means that optimizer managed to find
...@@ -9619,7 +9621,8 @@ best_extension_by_limited_search(JOIN *join, ...@@ -9619,7 +9621,8 @@ best_extension_by_limited_search(JOIN *join,
uint use_cond_selectivity, uint use_cond_selectivity,
table_map sort_nest_tables, table_map sort_nest_tables,
bool nest_created, bool nest_created,
bool limit_applied_to_nest) bool limit_applied_to_nest,
double sort_nest_records)
{ {
DBUG_ENTER("best_extension_by_limited_search"); DBUG_ENTER("best_extension_by_limited_search");
...@@ -9652,6 +9655,7 @@ best_extension_by_limited_search(JOIN *join, ...@@ -9652,6 +9655,7 @@ best_extension_by_limited_search(JOIN *join,
double original_record_count= record_count; double original_record_count= record_count;
record_count= COST_MULT(record_count, join->fraction_output_for_nest); record_count= COST_MULT(record_count, join->fraction_output_for_nest);
limit_applied_to_nest= TRUE; limit_applied_to_nest= TRUE;
sort_nest_records= record_count;
if (unlikely(thd->trace_started())) if (unlikely(thd->trace_started()))
{ {
...@@ -9706,7 +9710,7 @@ best_extension_by_limited_search(JOIN *join, ...@@ -9706,7 +9710,7 @@ best_extension_by_limited_search(JOIN *join,
POSITION loose_scan_pos; POSITION loose_scan_pos;
best_access_path(join, s, remaining_tables, join->positions, idx, best_access_path(join, s, remaining_tables, join->positions, idx,
disable_jbuf, record_count, position, &loose_scan_pos, disable_jbuf, record_count, position, &loose_scan_pos,
sort_nest_tables, nest_created); sort_nest_tables, nest_created, sort_nest_records);
/* /*
sort_nest_operation_here is set to TRUE here in the special case sort_nest_operation_here is set to TRUE here in the special case
...@@ -9810,7 +9814,10 @@ best_extension_by_limited_search(JOIN *join, ...@@ -9810,7 +9814,10 @@ best_extension_by_limited_search(JOIN *join,
if (join->is_index_with_ordering_allowed(idx) && if (join->is_index_with_ordering_allowed(idx) &&
s->check_if_index_satisfies_ordering(index_used)) s->check_if_index_satisfies_ordering(index_used))
{
limit_applied_to_nest= TRUE; limit_applied_to_nest= TRUE;
sort_nest_records= partial_join_cardinality;
}
if (!nest_created && if (!nest_created &&
(join->prefix_resolves_ordering || (join->prefix_resolves_ordering ||
...@@ -9839,7 +9846,8 @@ best_extension_by_limited_search(JOIN *join, ...@@ -9839,7 +9846,8 @@ best_extension_by_limited_search(JOIN *join,
prune_level, prune_level,
use_cond_selectivity, use_cond_selectivity,
sort_nest_tables | real_table_bit, sort_nest_tables | real_table_bit,
TRUE, limit_applied_to_nest)) TRUE, limit_applied_to_nest,
sort_nest_records))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
if (!(join->is_index_with_ordering_allowed(idx) && if (!(join->is_index_with_ordering_allowed(idx) &&
s->check_if_index_satisfies_ordering(index_used))) s->check_if_index_satisfies_ordering(index_used)))
...@@ -9857,8 +9865,9 @@ best_extension_by_limited_search(JOIN *join, ...@@ -9857,8 +9865,9 @@ best_extension_by_limited_search(JOIN *join,
use_cond_selectivity, use_cond_selectivity,
nest_created ? sort_nest_tables : nest_created ? sort_nest_tables :
sort_nest_tables | real_table_bit, sort_nest_tables | real_table_bit,
nest_created, nest_created || limit_applied_to_nest,
limit_applied_to_nest)) limit_applied_to_nest,
sort_nest_records))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
trace_rest.end(); trace_rest.end();
...@@ -9866,6 +9875,7 @@ best_extension_by_limited_search(JOIN *join, ...@@ -9866,6 +9875,7 @@ best_extension_by_limited_search(JOIN *join,
{ {
limit_applied_to_nest= FALSE; limit_applied_to_nest= FALSE;
join->positions[idx].sort_nest_operation_here= FALSE; join->positions[idx].sort_nest_operation_here= FALSE;
sort_nest_records= DBL_MAX;
} }
swap_variables(JOIN_TAB*, join->best_ref[idx], *pos); swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
} }
...@@ -10236,8 +10246,8 @@ cache_record_length_for_nest(JOIN *join,uint idx) ...@@ -10236,8 +10246,8 @@ cache_record_length_for_nest(JOIN *join,uint idx)
double double
prev_record_reads(const POSITION *positions, uint idx, table_map found_ref, prev_record_reads(const POSITION *positions, uint idx, table_map found_ref,
table_map sort_nest_tables, table_map sort_nest_tables, bool nest_created,
double fraction_output_for_nest) double sort_nest_records)
{ {
double found=1.0; double found=1.0;
const POSITION *pos_end= positions - 1; const POSITION *pos_end= positions - 1;
...@@ -10247,8 +10257,11 @@ prev_record_reads(const POSITION *positions, uint idx, table_map found_ref, ...@@ -10247,8 +10257,11 @@ prev_record_reads(const POSITION *positions, uint idx, table_map found_ref,
if (pos->table->table->map & found_ref) if (pos->table->table->map & found_ref)
{ {
found_ref|= pos->ref_depend_map; found_ref|= pos->ref_depend_map;
if (pos->table->table->map & sort_nest_tables) if (nest_created && pos->table->table->map & sort_nest_tables)
{
apply_limit= TRUE; apply_limit= TRUE;
break;
}
/* /*
For the case of "t1 LEFT JOIN t2 ON ..." where t2 is a const table For the case of "t1 LEFT JOIN t2 ON ..." where t2 is a const table
with no matching row we will get position[t2].records_read==0. with no matching row we will get position[t2].records_read==0.
...@@ -10272,8 +10285,15 @@ prev_record_reads(const POSITION *positions, uint idx, table_map found_ref, ...@@ -10272,8 +10285,15 @@ prev_record_reads(const POSITION *positions, uint idx, table_map found_ref,
} }
} }
} }
/*
This needs to be done only once if the nest is created because we
would be referring to the context post sorting.
*/
if (apply_limit) if (apply_limit)
found= COST_MULT(found, fraction_output_for_nest); {
DBUG_ASSERT(sort_nest_records != DBL_MAX);
found= COST_MULT(found, sort_nest_records);
}
return found; return found;
} }
...@@ -17351,7 +17371,7 @@ void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab, ...@@ -17351,7 +17371,7 @@ void optimize_wo_join_buffering(JOIN *join, uint first_tab, uint last_tab,
join->positions, i, join->positions, i,
TRUE, rec_count, TRUE, rec_count,
&pos, &loose_scan_pos, &pos, &loose_scan_pos,
0, FALSE); 0, FALSE, DBL_MAX);
} }
else else
pos= join->positions[i]; pos= join->positions[i];
......
...@@ -881,7 +881,7 @@ class LooseScan_picker : public Semi_join_strategy_picker ...@@ -881,7 +881,7 @@ class LooseScan_picker : public Semi_join_strategy_picker
struct st_position *pos, struct st_position *pos,
struct st_position *loose_scan_pos, struct st_position *loose_scan_pos,
table_map sort_nest_tables, table_map sort_nest_tables,
bool nest_created); bool nest_created, double sort_nest_records);
friend bool get_best_combination(JOIN *join); friend bool get_best_combination(JOIN *join);
friend int setup_semijoin_loosescan(JOIN *join); friend int setup_semijoin_loosescan(JOIN *join);
friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join); friend void fix_semijoin_strategies_for_picked_join_order(JOIN *join);
...@@ -2291,7 +2291,8 @@ void best_access_path(JOIN *join, JOIN_TAB *s, ...@@ -2291,7 +2291,8 @@ void best_access_path(JOIN *join, JOIN_TAB *s,
const POSITION *join_positions, uint idx, const POSITION *join_positions, uint idx,
bool disable_jbuf, double record_count, bool disable_jbuf, double record_count,
POSITION *pos, POSITION *loose_scan_pos, POSITION *pos, POSITION *loose_scan_pos,
table_map sort_nest_tables, bool nest_created); table_map sort_nest_tables, bool nest_created,
double sort_nest_records);
bool cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref); bool cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref);
bool error_if_full_join(JOIN *join); bool error_if_full_join(JOIN *join);
int report_error(TABLE *table, int error); int report_error(TABLE *table, int error);
...@@ -2672,7 +2673,7 @@ bool open_tmp_table(TABLE *table); ...@@ -2672,7 +2673,7 @@ bool open_tmp_table(TABLE *table);
void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps); void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps);
double prev_record_reads(const POSITION *positions, uint idx, table_map found_ref, double prev_record_reads(const POSITION *positions, uint idx, table_map found_ref,
table_map sort_nest_tables, table_map sort_nest_tables,
double fraction_output_for_nest); bool nest_created, double sort_nest_records);
void fix_list_after_tbl_changes(SELECT_LEX *new_parent, List<TABLE_LIST> *tlist); void fix_list_after_tbl_changes(SELECT_LEX *new_parent, List<TABLE_LIST> *tlist);
double get_tmp_table_lookup_cost(THD *thd, double row_count, ulong row_size); double get_tmp_table_lookup_cost(THD *thd, double row_count, ulong row_size);
......
...@@ -1039,7 +1039,7 @@ int get_best_index_for_order_by_limit(JOIN_TAB *tab, ...@@ -1039,7 +1039,7 @@ int get_best_index_for_order_by_limit(JOIN_TAB *tab,
double save_read_time= *read_time; double save_read_time= *read_time;
double save_records= *records; double save_records= *records;
double est_records= *records; double est_records= *records;
double fanout= MY_MAX(1.0, cardinality / est_records); double fanout= cardinality / est_records;
int best_index=-1; int best_index=-1;
trace_index_for_ordering.add("rows_estimation", est_records); trace_index_for_ordering.add("rows_estimation", est_records);
Json_writer_array considered_indexes(thd, "considered_indexes"); Json_writer_array considered_indexes(thd, "considered_indexes");
......
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