MDEV-26996 Support descending indexes in the range optimizer

- Code cleanup
- Disable "Using index for GROUP BY" over indexes with DESC keyparts
This commit is contained in:
Sergei Petrunia 2021-12-14 16:39:37 +03:00 committed by Sergei Golubchik
parent 3a82c256da
commit cbfe6a5e86
6 changed files with 82 additions and 47 deletions

View File

@ -154,5 +154,28 @@ json_detailed(json_extract(trace, '$**.range_access_plan.ranges'))
"(4,80) <= (a,b) <= (2,50)" "(4,80) <= (a,b) <= (2,50)"
] ]
] ]
set optimizer_trace=default;
drop table t2; drop table t2;
#
# Check that "Using index for group-by" is disabled (it's not supported, yet)
#
CREATE TABLE t1 (p int NOT NULL, a int NOT NULL, PRIMARY KEY (p,a desc));
insert into t1 select 2,seq from seq_0_to_1000;
EXPLAIN select MIN(a) from t1 where p = 2 group by p;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref PRIMARY PRIMARY 4 const 1000 Using index
select json_detailed(json_extract(trace, '$**.potential_group_range_indexes'))
from information_schema.optimizer_trace;
json_detailed(json_extract(trace, '$**.potential_group_range_indexes'))
[
[
{
"index": "PRIMARY",
"usable": false,
"cause": "Reverse-ordered (not supported yet)"
}
]
]
drop table t1;
set optimizer_trace=default;

View File

@ -73,5 +73,16 @@ select * from t2 where a between 2 and 4 and b between 50 and 80;
select json_detailed(json_extract(trace, '$**.range_access_plan.ranges')) select json_detailed(json_extract(trace, '$**.range_access_plan.ranges'))
from information_schema.optimizer_trace; from information_schema.optimizer_trace;
set optimizer_trace=default;
drop table t2; drop table t2;
--echo #
--echo # Check that "Using index for group-by" is disabled (it's not supported, yet)
--echo #
CREATE TABLE t1 (p int NOT NULL, a int NOT NULL, PRIMARY KEY (p,a desc));
insert into t1 select 2,seq from seq_0_to_1000;
EXPLAIN select MIN(a) from t1 where p = 2 group by p;
select json_detailed(json_extract(trace, '$**.potential_group_range_indexes'))
from information_schema.optimizer_trace;
drop table t1;
set optimizer_trace=default;

View File

@ -1201,8 +1201,8 @@ EXPLAIN SELECT DISTINCT a FROM t1 {
}, },
{ {
"index": "a", "index": "a",
"key_parts": ["a"], "usable": true,
"usable": true "key_parts": ["a"]
} }
], ],
"best_covering_index_scan": { "best_covering_index_scan": {
@ -1384,8 +1384,8 @@ EXPLAIN SELECT MIN(d) FROM t1 where b=2 and c=3 group by a {
"potential_range_indexes": [ "potential_range_indexes": [
{ {
"index": "a", "index": "a",
"key_parts": ["a", "b", "c", "d"], "usable": true,
"usable": true "key_parts": ["a", "b", "c", "d"]
} }
], ],
"best_covering_index_scan": { "best_covering_index_scan": {
@ -1583,8 +1583,8 @@ EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id {
"potential_range_indexes": [ "potential_range_indexes": [
{ {
"index": "id", "index": "id",
"key_parts": ["id", "a"], "usable": true,
"usable": true "key_parts": ["id", "a"]
} }
], ],
"best_covering_index_scan": { "best_covering_index_scan": {
@ -1771,8 +1771,8 @@ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id {
"potential_range_indexes": [ "potential_range_indexes": [
{ {
"index": "id", "index": "id",
"key_parts": ["id", "a"], "usable": true,
"usable": true "key_parts": ["id", "a"]
} }
], ],
"best_covering_index_scan": { "best_covering_index_scan": {
@ -2010,13 +2010,13 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
}, },
{ {
"index": "a_c", "index": "a_c",
"key_parts": ["a", "c"], "usable": true,
"usable": true "key_parts": ["a", "c"]
}, },
{ {
"index": "a_b", "index": "a_b",
"key_parts": ["a", "b"], "usable": true,
"usable": true "key_parts": ["a", "b"]
} }
], ],
"setup_range_conditions": [], "setup_range_conditions": [],
@ -2213,8 +2213,8 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
}, },
{ {
"index": "a_c", "index": "a_c",
"key_parts": ["a", "c"], "usable": true,
"usable": true "key_parts": ["a", "c"]
}, },
{ {
"index": "a_b", "index": "a_b",
@ -3233,18 +3233,18 @@ explain select * from t1 where pk = 2 and a=5 and b=1 {
"potential_range_indexes": [ "potential_range_indexes": [
{ {
"index": "pk", "index": "pk",
"key_parts": ["pk"], "usable": true,
"usable": true "key_parts": ["pk"]
}, },
{ {
"index": "pk_a", "index": "pk_a",
"key_parts": ["pk", "a"], "usable": true,
"usable": true "key_parts": ["pk", "a"]
}, },
{ {
"index": "pk_a_b", "index": "pk_a_b",
"key_parts": ["pk", "a", "b"], "usable": true,
"usable": true "key_parts": ["pk", "a", "b"]
} }
], ],
"best_covering_index_scan": { "best_covering_index_scan": {
@ -3751,8 +3751,8 @@ explain delete from t0 where t0.a<3 {
"potential_range_indexes": [ "potential_range_indexes": [
{ {
"index": "a", "index": "a",
"key_parts": ["a"], "usable": true,
"usable": true "key_parts": ["a"]
} }
], ],
"setup_range_conditions": [], "setup_range_conditions": [],
@ -3889,8 +3889,8 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 {
"potential_range_indexes": [ "potential_range_indexes": [
{ {
"index": "a", "index": "a",
"key_parts": ["a"], "usable": true,
"usable": true "key_parts": ["a"]
} }
], ],
"best_covering_index_scan": { "best_covering_index_scan": {
@ -3954,8 +3954,8 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 {
"potential_range_indexes": [ "potential_range_indexes": [
{ {
"index": "a", "index": "a",
"key_parts": ["a"], "usable": true,
"usable": true "key_parts": ["a"]
} }
], ],
"best_covering_index_scan": { "best_covering_index_scan": {

View File

@ -78,13 +78,13 @@ explain select * from t1 where a=1 or b=1 {
"potential_range_indexes": [ "potential_range_indexes": [
{ {
"index": "a", "index": "a",
"key_parts": ["a"], "usable": true,
"usable": true "key_parts": ["a"]
}, },
{ {
"index": "b", "index": "b",
"key_parts": ["b"], "usable": true,
"usable": true "key_parts": ["b"]
}, },
{ {
"index": "c", "index": "c",

View File

@ -93,13 +93,13 @@ explain select * from t1 where pk1 != 0 and key1 = 1 {
"potential_range_indexes": [ "potential_range_indexes": [
{ {
"index": "PRIMARY", "index": "PRIMARY",
"key_parts": ["pk1", "pk2"], "usable": true,
"usable": true "key_parts": ["pk1", "pk2"]
}, },
{ {
"index": "key1", "index": "key1",
"key_parts": ["key1"], "usable": true,
"usable": true "key_parts": ["key1"]
}, },
{ {
"index": "key2", "index": "key2",

View File

@ -2809,12 +2809,11 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
trace_idx_details.add("usable", false).add("cause", "fulltext"); trace_idx_details.add("usable", false).add("cause", "fulltext");
continue; // ToDo: ft-keys in non-ft ranges, if possible SerG continue; // ToDo: ft-keys in non-ft ranges, if possible SerG
} }
trace_idx_details.add("usable", true);
param.key[param.keys]=key_parts; param.key[param.keys]=key_parts;
key_part_info= key_info->key_part; key_part_info= key_info->key_part;
uint cur_key_len= 0; uint cur_key_len= 0;
Json_writer_array trace_keypart(thd, "key_parts"); Json_writer_array trace_keypart(thd, "key_parts");
bool unusable_has_desc_keyparts= false;
for (uint part= 0 ; part < n_key_parts ; for (uint part= 0 ; part < n_key_parts ;
part++, key_parts++, key_part_info++) part++, key_parts++, key_part_info++)
{ {
@ -2829,18 +2828,9 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
(key_info->flags & HA_SPATIAL) ? Field::itMBR : Field::itRAW; (key_info->flags & HA_SPATIAL) ? Field::itMBR : Field::itRAW;
/* Only HA_PART_KEY_SEG is used */ /* Only HA_PART_KEY_SEG is used */
key_parts->flag= (uint8) key_part_info->key_part_flag; key_parts->flag= (uint8) key_part_info->key_part_flag;
if (key_part_info->key_part_flag & HA_REVERSE_SORT)
unusable_has_desc_keyparts= true;
trace_keypart.add(key_parts->field->field_name); trace_keypart.add(key_parts->field->field_name);
} }
trace_keypart.end(); trace_keypart.end();
trace_idx_details.add("usable", !unusable_has_desc_keyparts);
unusable_has_desc_keyparts= false;
if (unusable_has_desc_keyparts) // TODO MDEV-13756
{
key_parts= param.key[param.keys];
continue;
}
param.real_keynr[param.keys++]=idx; param.real_keynr[param.keys++]=idx;
if (cur_key_len > max_key_len) if (cur_key_len > max_key_len)
max_key_len= cur_key_len; max_key_len= cur_key_len;
@ -13837,6 +13827,17 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
goto next_index; goto next_index;
} }
{
for (uint i= 0; i < table->actual_n_key_parts(cur_index_info); i++)
{
if (cur_index_info->key_part[i].key_part_flag & HA_REVERSE_SORT)
{
cause="Reverse-ordered (not supported yet)";
goto next_index;
}
}
}
/* /*
This function is called on the precondition that the index is covering. This function is called on the precondition that the index is covering.
Therefore if the GROUP BY list contains more elements than the index, Therefore if the GROUP BY list contains more elements than the index,