revision-id: a555a12a11be7e5f13fca04dcfb757110e65793e parent(s): edb3a32c6cc06407efc96a30a6c7948fb9628ace committer: Sergei Petrunia branch nick: 10.1-r2 timestamp: 2018-09-09 21:07:46 +0300 message: 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). --- sql/sql_select.cc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d1b1c17..5cbf515 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -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.set_bit(best_key); // only best_key. 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, join->select_options & OPTION_FOUND_ROWS ? HA_POS_ERROR : join->unit->select_limit_cnt, TRUE, FALSE, FALSE); + + if (cond_saved) + select->cond= saved_cond; } order_direction= best_key_direction; /*