1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-6796: Unable to skip filesort when using implicit extended key

Re-work test_if_order_by_key() to work correctly for extended indexes.
This commit is contained in:
Sergei Petrunia
2014-09-26 15:54:35 +04:00
parent 15ad0d0bb7
commit 0b15557c8f
4 changed files with 149 additions and 68 deletions

View File

@ -46,3 +46,45 @@ EXPLAIN SELECT * FROM t2 WHERE pk1=9 AND fd5 < 500 ORDER B
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range PRIMARY,ux_pk1_fd5 ux_pk1_fd5 13 NULL 137 Using where
drop table t0,t1, t2;
#
# MDEV-6796: Unable to skip filesort when using implicit extended key
#
CREATE TABLE t1 (
pk1 int(11) NOT NULL,
pk2 varchar(64) NOT NULL,
col1 varchar(16) DEFAULT NULL,
PRIMARY KEY (pk1,pk2),
KEY key1 (pk1,col1)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE t2 (
pk1 int(11) NOT NULL,
pk2 varchar(64) NOT NULL,
col1 varchar(16) DEFAULT NULL,
PRIMARY KEY (pk1,pk2),
KEY key1 (pk1,col1,pk2)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `t1` VALUES
(12321321,'a8f5f167f44f4964e6c998dee827110c','video'),
(12321321,'d77a17a3659ffa60c54e0ea17b6c6d16','video'),
(12321321,'wwafdsafdsafads','video'),
(12321321,'696aa249f0738e8181957dd57c2d7d0b','video-2014-09-23'),
(12321321,'802f9f29584b486f356693e3aa4ef0af','video=sdsd'),
(12321321,'2f94543ff74aab82e9a058b4e8316d75','video=sdsdsds'),
(12321321,'c1316b9df0d203fd1b9035308de52a0a','video=sdsdsdsdsd');
insert into t2 select * from t1;
# this must not use filesort:
explain SELECT pk2
FROM t1 USE INDEX(key1)
WHERE pk1 = 123
AND col1 = 'video'
ORDER BY pk2 DESC LIMIT 21;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref key1 key1 55 const,const 1 Using where; Using index
# this must not use filesort, either:
explain SELECT pk2
FROM t2 USE INDEX(key1)
WHERE pk1 = 123 AND col1 = 'video'
ORDER BY pk2 DESC LIMIT 21;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref key1 key1 55 const,const 1 Using where; Using index
drop table t1, t2;

View File

@ -41,3 +41,50 @@ EXPLAIN SELECT * FROM t2 USE INDEX(ux_pk1_fd5) WHERE pk1=9 AND fd5 < 500 ORDER B
EXPLAIN SELECT * FROM t2 WHERE pk1=9 AND fd5 < 500 ORDER BY fd5 DESC LIMIT 10;
drop table t0,t1, t2;
--echo #
--echo # MDEV-6796: Unable to skip filesort when using implicit extended key
--echo #
CREATE TABLE t1 (
pk1 int(11) NOT NULL,
pk2 varchar(64) NOT NULL,
col1 varchar(16) DEFAULT NULL,
PRIMARY KEY (pk1,pk2),
KEY key1 (pk1,col1)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE t2 (
pk1 int(11) NOT NULL,
pk2 varchar(64) NOT NULL,
col1 varchar(16) DEFAULT NULL,
PRIMARY KEY (pk1,pk2),
KEY key1 (pk1,col1,pk2)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `t1` VALUES
(12321321,'a8f5f167f44f4964e6c998dee827110c','video'),
(12321321,'d77a17a3659ffa60c54e0ea17b6c6d16','video'),
(12321321,'wwafdsafdsafads','video'),
(12321321,'696aa249f0738e8181957dd57c2d7d0b','video-2014-09-23'),
(12321321,'802f9f29584b486f356693e3aa4ef0af','video=sdsd'),
(12321321,'2f94543ff74aab82e9a058b4e8316d75','video=sdsdsds'),
(12321321,'c1316b9df0d203fd1b9035308de52a0a','video=sdsdsdsdsd');
insert into t2 select * from t1;
--echo # this must not use filesort:
explain SELECT pk2
FROM t1 USE INDEX(key1)
WHERE pk1 = 123
AND col1 = 'video'
ORDER BY pk2 DESC LIMIT 21;
--echo # this must not use filesort, either:
explain SELECT pk2
FROM t2 USE INDEX(key1)
WHERE pk1 = 123 AND col1 = 'video'
ORDER BY pk2 DESC LIMIT 21;
drop table t1, t2;

View File

@ -281,6 +281,12 @@ public:
LEX_STRING comment;
/* Field is part of the following keys */
key_map key_start, part_of_key, part_of_key_not_clustered;
/*
Bitmap of indexes that have records ordered by col1, ... this_field, ...
For example, INDEX (col(prefix_n)) is not present in col.part_of_sortkey.
*/
key_map part_of_sortkey;
/*
We use three additional unireg types for TIMESTAMP to overcome limitation

View File

@ -15044,6 +15044,11 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
@retval true can be used
@retval false cannot be used
*/
/*
psergey-todo: this returns false for int_column='1234' (here '1234' is a
constant. Need to discuss this with Bar).
*/
static bool
test_if_equality_guarantees_uniqueness(Item *l, Item *r)
{
@ -19676,12 +19681,21 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
{
KEY_PART_INFO *key_part,*key_part_end;
key_part=table->key_info[idx].key_part;
key_part_end=key_part+table->key_info[idx].user_defined_key_parts;
key_part_end=key_part + table->key_info[idx].ext_key_parts;
key_part_map const_key_parts=table->const_key_parts[idx];
uint user_defined_kp= table->key_info[idx].user_defined_key_parts;
int reverse=0;
uint key_parts;
my_bool on_pk_suffix= FALSE;
bool have_pk_suffix= false;
uint pk= table->s->primary_key;
DBUG_ENTER("test_if_order_by_key");
if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
table->key_info[idx].ext_key_part_map &&
pk != MAX_KEY && pk != idx)
{
have_pk_suffix= true;
}
for (; order ; order=order->next, const_key_parts>>=1)
{
@ -19694,58 +19708,37 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
*/
for (; const_key_parts & 1 ; const_key_parts>>= 1)
key_part++;
/*
This check was in this function historically (although I think it's
better to check it outside of this function):
if (key_part >= key_part_end)
"Test if the primary key parts were all const (i.e. there's one row).
The sorting doesn't matter"
So, we're checking that
(1) this is an extended key
(2) we've reached its end
*/
key_parts= (key_part - table->key_info[idx].key_part);
if (have_pk_suffix &&
reverse == 0 && // all were =const so far
key_parts == table->key_info[idx].ext_key_parts &&
table->const_key_parts[pk] == PREV_BITS(uint,
table->key_info[pk].
user_defined_key_parts))
{
/*
We are at the end of the key. Check if the engine has the primary
key as a suffix to the secondary keys. If it has continue to check
the primary key as a suffix.
key_parts= 0;
reverse= 1; // Key is ok to use
goto ok;
}
if (key_part == key_part_end)
{
/*
There are some items left in ORDER BY that we don't
*/
if (!on_pk_suffix && (table->key_info[idx].ext_key_part_map & 1) &&
(table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
table->s->primary_key != MAX_KEY &&
table->s->primary_key != idx)
{
KEY_PART_INFO *start,*end;
uint pk_part_idx= 0;
on_pk_suffix= TRUE;
start= key_part= table->key_info[table->s->primary_key].key_part;
const_key_parts=table->const_key_parts[table->s->primary_key];
/*
Calculate true key_part_end and const_key_parts
(we have to stop as first not continous primary key part)
*/
for (key_part_end= key_part,
end= key_part+table->key_info[table->s->primary_key].user_defined_key_parts;
key_part_end < end; key_part_end++, pk_part_idx++)
{
/* Found hole in the pk_parts; Abort */
if (!(table->key_info[idx].ext_key_part_map &
(((key_part_map) 1) << pk_part_idx)))
break;
}
/* Adjust const_key_parts */
const_key_parts&= (((key_part_map) 1) << pk_part_idx) -1;
for (; const_key_parts & 1 ; const_key_parts>>= 1)
key_part++;
/*
Test if the primary key parts were all const (i.e. there's one row).
The sorting doesn't matter.
*/
if (key_part == start+table->key_info[table->s->primary_key].user_defined_key_parts &&
reverse == 0)
{
key_parts= 0;
reverse= 1; // Key is ok to use
goto ok;
}
}
else
DBUG_RETURN(0);
DBUG_RETURN(0);
}
if (key_part->field != field || !field->part_of_sortkey.is_set(idx))
@ -19760,27 +19753,20 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
if (key_part < key_part_end)
key_part++;
}
if (on_pk_suffix)
{
uint used_key_parts_secondary= table->key_info[idx].user_defined_key_parts;
uint used_key_parts_pk=
(uint) (key_part - table->key_info[table->s->primary_key].key_part);
key_parts= used_key_parts_pk + used_key_parts_secondary;
if (reverse == -1 &&
(!(table->file->index_flags(idx, used_key_parts_secondary - 1, 1) &
HA_READ_PREV) ||
!(table->file->index_flags(table->s->primary_key,
used_key_parts_pk - 1, 1) & HA_READ_PREV)))
reverse= 0; // Index can't be used
}
else
key_parts= (uint) (key_part - table->key_info[idx].key_part);
if (reverse == -1 &&
!(table->file->index_flags(idx, user_defined_kp, 1) & HA_READ_PREV))
reverse= 0; // Index can't be used
if (have_pk_suffix && reverse == -1)
{
key_parts= (uint) (key_part - table->key_info[idx].key_part);
if (reverse == -1 &&
!(table->file->index_flags(idx, key_parts-1, 1) & HA_READ_PREV))
uint pk_parts= table->key_info[pk].user_defined_key_parts;
if (!table->file->index_flags(pk, pk_parts, 1) & HA_READ_PREV)
reverse= 0; // Index can't be used
}
ok:
if (used_key_parts != NULL)
*used_key_parts= key_parts;