Bug #46376 | Optimizer choose wrong index even when where clause and order-by are covered | ||
---|---|---|---|
Submitted: | 24 Jul 2009 17:05 | Modified: | 29 Jul 2009 8:39 |
Reporter: | T C | Email Updates: | |
Status: | Verified | Impact on me: | |
Category: | MySQL Server: Optimizer | Severity: | S5 (Performance) |
Version: | 5.0.85, 5.1.36, 5.1.38, 5.1.39 | OS: | Windows (XP) |
Assigned to: | Tor Didriksen | CPU Architecture: | Any |
Tags: | INDEX, Optimizer, performance |
[24 Jul 2009 17:05]
T C
[24 Jul 2009 17:39]
Valeriy Kravchuk
Thank you for the problem report. I do not see how PRIMARY key can be used for this query at all (it does NOT cover WHERE and ORDER BY), so, please, provide a complete repeatable test case, with data.
[24 Jul 2009 18:52]
T C
create table casRecord ( Id integer not null auto_increment, Uuid binary(16) not null, RecordDefinitionName varchar(64) not null, RecordName varchar(255) not null, Active tinyint not null default 1, RecordType tinyint not null default 0, constraint pk_casRecord primary key (Id), constraint ix_casRecord_2 unique index (Uuid), index ix_casRecord_3 (RecordName) ); create table casRecordField ( Id integer not null auto_increment, RecordId integer not null, Uuid binary(16) not null, GroupNumber integer not null default 0, ShortName varchar(64) not null, Value longtext null, constraint pk_casRecordField primary key (Id), constraint fk_casRecordField_to_casRecord foreign key (RecordId) references casRecord (Id), constraint ix_casRecordField_1 unique index (RecordId, GroupNumber, ShortName), constraint ix_casRecordField_2 unique index (RecordId, Id), constraint ix_casRecordField_3 unique index (Uuid) ); delimiter // create procedure sp_loadTestData() begin declare cnt int default 1000; declare childCnt int default 15; declare rId int; while cnt > 0 do begin insert into casRecord (Uuid, RecordDefinitionName, RecordName) values (unhex(replace(uuid(), '-', '')), 'Test', concat('TestName', cnt)); select last_insert_id() into rId; set childCnt = 15; while childCnt > 0 do begin insert into casRecordField(RecordId, Uuid, GroupNumber, ShortName) values (rId, unhex(replace(uuid(), '-', '')), 0, concat('Name', childCnt)); set childCnt = childCnt - 1; end; end while; set cnt = cnt - 1; end; end while; end // delimiter ; call sp_loadTestData(); explain select rf.* from casRecordField rf where rf.RecordId= 601 order by rf.RecordId, rf.Id explain select rf.* from casRecordField rf force index(ix_casRecordField_2) where rf.RecordId = 701 order by rf.RecordId, rf.Id
[24 Jul 2009 19:15]
T C
One more note: the plan differs when you take the longtext field out of the selected column list. Maybe that's a clue?
[25 Jul 2009 7:56]
Valeriy Kravchuk
Thank you for the complete test case. On recent 5.1.38 from bzr with MyISAM table I've got proper index used by default: mysql> call sp_loadTestData(); Query OK, 1 row affected (9.84 sec) mysql> explain select rf.* from casRecordField rf where rf.RecordId= 601 order by rf.RecordId, rf.Id\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: rf type: ref possible_keys: ix_casRecordField_1,ix_casRecordField_2 key: ix_casRecordField_2 key_len: 4 ref: const rows: 12 Extra: Using where 1 row in set (0.00 sec) mysql> show table status like 'casRecordField'\G *************************** 1. row *************************** Name: casRecordField Engine: MyISAM Version: 10 Row_format: Dynamic Rows: 15000 Avg_row_length: 36 Data_length: 540000 Max_data_length: 281474976710655 Index_length: 1025024 Data_free: 0 Auto_increment: 15001 Create_time: 2009-07-25 10:22:27 Update_time: 2009-07-25 10:23:41 Check_time: NULL Collation: latin1_swedish_ci Checksum: NULL Create_options: Comment: 1 row in set (0.03 sec) But with InnoDB tables (it is reasonable to assume they are InnoDB...) I've got ix_casRecordField_1 index used (NOT PRIMARY): mysql> select version();+--------------+| version() |+--------------+| 5.1.38-debug | +--------------+1 row in set (0.00 sec)mysql> create table casRecord ( -> Id integer not null auto_increment, -> Uuid binary(16) not null, -> RecordDefinitionName varchar(64) not null, -> RecordName varchar(255) not null, -> Active tinyint not null default 1, -> RecordType tinyint not null default 0, -> constraint pk_casRecord primary key (Id), -> constraint ix_casRecord_2 unique index (Uuid), -> index ix_casRecord_3 (RecordName) -> ) engine=InnoDB; Query OK, 0 rows affected (0.14 sec) mysql> create table casRecordField ( -> Id integer not null auto_increment, -> RecordId integer not null, -> Uuid binary(16) not null, -> GroupNumber integer not null default 0, -> ShortName varchar(64) not null, -> Value longtext null, -> constraint pk_casRecordField primary key (Id), -> constraint fk_casRecordField_to_casRecord foreign key (RecordId) references casRecord -> (Id), -> constraint ix_casRecordField_1 unique index (RecordId, GroupNumber, ShortName), -> constraint ix_casRecordField_2 unique index (RecordId, Id), -> constraint ix_casRecordField_3 unique index (Uuid) -> ) engine=InnoDB; Query OK, 0 rows affected (0.40 sec) mysql> call sp_loadTestData(); Query OK, 1 row affected (22.44 sec) mysql> explain select rf.* from casRecordField rf where rf.RecordId= 601 order by rf.RecordId, -> rf.Id -> \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: rf type: ref possible_keys: ix_casRecordField_1,ix_casRecordField_2 key: ix_casRecordField_1 key_len: 4 ref: const rows: 15 Extra: Using where; Using filesort 1 row in set (0.01 sec) mysql> analyze table casRecordField; +---------------------+---------+----------+----------+ | Table | Op | Msg_type | Msg_text | +---------------------+---------+----------+----------+ | test.casrecordfield | analyze | status | OK | +---------------------+---------+----------+----------+ 1 row in set (0.01 sec) mysql> explain select rf.* from casRecordField rf where rf.RecordId= 601 order by rf.RecordId, rf.Id\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: rf type: ref possible_keys: ix_casRecordField_1,ix_casRecordField_2 key: ix_casRecordField_1 key_len: 4 ref: const rows: 15 Extra: Using where; Using filesort 1 row in set (0.00 sec) This is still a bug, as ix_casRecordField_2 can be used more efficiently to avoid filesort step. As only InnoDB is affected it seems to be a bug from "bug #28404 family".
[25 Jul 2009 8:00]
Valeriy Kravchuk
5.0.85 is also affected, so it does not look like a regression.
[27 Jul 2009 17:51]
T C
I'd say this is probably closer to bug#38745 For the time being the workaround is to use index hints in all order-by queries against large tables, since the current implementation seems to enjoy doing filesorts ;-)
[4 Mar 2010 8:47]
Manyi Lu
It depends on fix for BUG#46011.