Commit e63b84b9 authored by Sergei Petrunia's avatar Sergei Petrunia

MDEV-17155: Incorrect ORDER BY optimization: full index scan is used instead of range

The bug was this scenario:
1. Join optimizer picks a range plan on index IDX1
   (This index doesn't match the ORDER BY clause, so sorting will be needed)
2. Index Condition Pushdown pushes a part of WHERE down. The pushed
   condition is removed from SQL_SELECT::cond
3. test_if_skip_sort_order() figures that it's better to use IDX2
   (as it will match ORDER BY ... LIMIT and so will execute faster)

3.1 It sees that there was a possible range access on IDX2. It tries to
   construct it by calling SQL_SELECT::test_quick_select(), but alas,
   SQL_SELECT::cond doesn't have all parts of WHERE anymore.
   So it uses full index scan which is slow.

(The execution works fine because there's code further in test_if_skip_sort_order()
which "Unpushes" the index condition and restores the original WHERE clause.
It was just the test_quick_select call that suffered).
parent 038804d5
...@@ -21244,11 +21244,30 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, ...@@ -21244,11 +21244,30 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
tmp_map.clear_all(); // Force the creation of quick select tmp_map.clear_all(); // Force the creation of quick select
tmp_map.set_bit(best_key); // only best_key. tmp_map.set_bit(best_key); // only best_key.
select->quick= 0; select->quick= 0;
bool cond_saved= false;
Item *saved_cond;
/*
Index Condition Pushdown may have removed parts of the condition for
this table. Temporarily put them back because we want the whole
condition for the range analysis.
*/
if (select->pre_idx_push_select_cond)
{
saved_cond= select->cond;
select->cond= select->pre_idx_push_select_cond;
cond_saved= true;
}
select->test_quick_select(join->thd, tmp_map, 0, select->test_quick_select(join->thd, tmp_map, 0,
join->select_options & OPTION_FOUND_ROWS ? join->select_options & OPTION_FOUND_ROWS ?
HA_POS_ERROR : HA_POS_ERROR :
join->unit->select_limit_cnt, join->unit->select_limit_cnt,
TRUE, FALSE, FALSE); TRUE, FALSE, FALSE);
if (cond_saved)
select->cond= saved_cond;
} }
order_direction= best_key_direction; order_direction= best_key_direction;
/* /*
......
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