Skip to content

Commit ff8d400

Browse files
committed
MDEV-9457: Poor query plan chosen for ORDER BY query by a recent 10.1
Undo the change in test_if_skip_sort_order() that set ref_key=-1 when a variant of index_merge is used (was made in fix for MDEV-9021). It turned out that test_if_cheaper_ordering() call below assumes that ref_key=-1 means "no index is used", that is, "an inefficient full table scan is done". This is not the same as index_merge, index_merge can actually be quite efficient. So, ref_key=MAX_KEY denotes the fact that some index is used, not any given index.
1 parent 825f51d commit ff8d400

File tree

3 files changed

+93
-5
lines changed

3 files changed

+93
-5
lines changed

mysql-test/r/order_by_innodb.result

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,40 @@ a b c d
1111
8 NULL 9 NULL
1212
8 NULL 10 NULL
1313
DROP TABLE t1;
14+
#
15+
# MDEV-9457: Poor query plan chosen for ORDER BY query by a recent 10.1
16+
#
17+
create table t0 (a int);
18+
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
19+
create table t1 (
20+
pk int primary key,
21+
key1 int,
22+
key2 int,
23+
col1 char(255),
24+
key(key1),
25+
key(key2)
26+
) engine=innodb;
27+
set @a=-1;
28+
insert into t1
29+
select
30+
@a:=@a+1,
31+
@a,
32+
@a,
33+
repeat('abcd', 63)
34+
from t0 A, t0 B, t0 C, t0 D;
35+
# The following must NOT use 'index' on PK.
36+
# It should use index_merge(key1,key2) + filesort
37+
explain
38+
select *
39+
from t1
40+
where key1<3 or key2<3
41+
order by pk;
42+
id select_type table type possible_keys key key_len ref rows Extra
43+
1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL # Using sort_union(key1,key2); Using where; Using filesort
44+
explain
45+
select *
46+
from t1
47+
where key1<3 or key2<3;
48+
id select_type table type possible_keys key key_len ref rows Extra
49+
1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL # Using sort_union(key1,key2); Using where
50+
drop table t0, t1;

mysql-test/t/order_by_innodb.test

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,43 @@ SELECT * FROM t1 WHERE a = 8 AND (b = 1 OR b IS NULL) ORDER BY c;
2121

2222
DROP TABLE t1;
2323

24+
--echo #
25+
--echo # MDEV-9457: Poor query plan chosen for ORDER BY query by a recent 10.1
26+
--echo #
27+
create table t0 (a int);
28+
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
29+
30+
create table t1 (
31+
pk int primary key,
32+
key1 int,
33+
key2 int,
34+
col1 char(255),
35+
key(key1),
36+
key(key2)
37+
) engine=innodb;
38+
39+
set @a=-1;
40+
insert into t1
41+
select
42+
@a:=@a+1,
43+
@a,
44+
@a,
45+
repeat('abcd', 63)
46+
from t0 A, t0 B, t0 C, t0 D;
47+
48+
--echo # The following must NOT use 'index' on PK.
49+
--echo # It should use index_merge(key1,key2) + filesort
50+
--replace_column 9 #
51+
explain
52+
select *
53+
from t1
54+
where key1<3 or key2<3
55+
order by pk;
56+
57+
--replace_column 9 #
58+
explain
59+
select *
60+
from t1
61+
where key1<3 or key2<3;
62+
63+
drop table t0, t1;

sql/sql_select.cc

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20777,7 +20777,15 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
2077720777
quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT ||
2077820778
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
2077920779
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT)
20780-
ref_key= -1;
20780+
{
20781+
/*
20782+
we set ref_key=MAX_KEY instead of -1, because test_if_cheaper ordering
20783+
assumes that "ref_key==-1" means doing full index scan.
20784+
(This is not very straightforward and we got into this situation for
20785+
historical reasons. Should be fixed at some point).
20786+
*/
20787+
ref_key= MAX_KEY;
20788+
}
2078120789
else
2078220790
{
2078320791
ref_key= select->quick->index;
@@ -25442,8 +25450,12 @@ static bool get_range_limit_read_cost(const JOIN_TAB *tab,
2544225450
@param table Table if tab == NULL or tab->table
2544325451
@param usable_keys Key map to find a cheaper key in
2544425452
@param ref_key
25445-
* 0 <= key < MAX_KEY - key number (hint) to start the search
25446-
* -1 - no key number provided
25453+
0 <= key < MAX_KEY - Key that is currently used for finding
25454+
row
25455+
MAX_KEY - means index_merge is used
25456+
-1 - means we're currently not using an
25457+
index to find rows.
25458+
2544725459
@param select_limit LIMIT value
2544825460
@param [out] new_key Key number if success, otherwise undefined
2544925461
@param [out] new_key_direction Return -1 (reverse) or +1 if success,
@@ -25472,7 +25484,6 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
2547225484
uint *saved_best_key_parts)
2547325485
{
2547425486
DBUG_ENTER("test_if_cheaper_ordering");
25475-
DBUG_ASSERT(ref_key < int(MAX_KEY));
2547625487
/*
2547725488
Check whether there is an index compatible with the given order
2547825489
usage of which is cheaper than usage of the ref_key index (ref_key>=0)
@@ -25537,7 +25548,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
2553725548
Calculate the selectivity of the ref_key for REF_ACCESS. For
2553825549
RANGE_ACCESS we use table->quick_condition_rows.
2553925550
*/
25540-
if (ref_key >= 0 && !is_hash_join_key_no(ref_key) && tab->type == JT_REF)
25551+
if (ref_key >= 0 && ref_key != MAX_KEY && tab->type == JT_REF)
2554125552
{
2554225553
if (table->quick_keys.is_set(ref_key))
2554325554
refkey_rows_estimate= table->quick_rows[ref_key];

0 commit comments

Comments
 (0)