Bug #36109 index on part of varchar field is not used when it could be
Submitted: 16 Apr 2008 5:12 Modified: 10 Jul 2009 9:39
Reporter: Ben Krug Email Updates:
Status: No Feedback Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S3 (Non-critical)
Version:5.0.44, 5.0.51, 5.0.66a, 5.1.26-rc OS:Any
Assigned to: Assigned Account CPU Architecture:Any

[16 Apr 2008 5:12] Ben Krug
Description:
An compound index using the first n characters of a varchar field is not being used for an equality test with a string of (n-1) characters when done one way, but not when done another way.  The index should suffice and be used.

How to repeat:
create table bentest (
id int not null auto_increment,
stamptime timestamp default current_timestamp,
name varchar(10),
primary key (id),
key name_idx (stamptime,name(4))
) engine=MyISAM;

insert into bentest (name) values ('one');
insert into bentest (name) values ('two');
insert into bentest (name) values ('three');
insert into bentest (name) values ('four');
insert into bentest (name) values ('five');
insert into bentest (name) values ('six');
insert into bentest (name) values ('seven');
insert into bentest (name) values ('seven2');
insert into bentest (name) values ('seven3');
insert into bentest (name) values ('eight');

explain select count(name) from bentest where stamptime>'2007-01-01 00:00:00' and name='one';
--index not used here, although it could/should be?

+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | bentest | ALL  | name_idx      | NULL | NULL    | NULL |10    | Using where |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
1 row in set, 2 warnings (0.00 sec)

alter table bentest drop key name_idx;
alter table bentest add key name_idx (stamptime,name);

explain select count(name) from bentest where stamptime>'2007-01-01 00:00:00' and name='one';
--index on full field is used

+----+-------------+---------+-------+---------------+----------+---------+------+------+--------------------------+
| id | select_type | table   | type  | possible_keys | key      | key_len | ref | rows | Extra                    |
+----+-------------+---------+-------+---------------+----------+---------+------+------+--------------------------+
|  1 | SIMPLE      | bentest | index | name_idx      | name_idx | 37      | NULL |   10 | Using where; Using index |
+----+-------------+---------+-------+---------------+----------+---------+-----+------+--------------------------+
1 row in set, 2 warnings (0.03 sec)

alter table bentest drop key name_idx;
alter table bentest add key name_idx (name(4),stamptime);

explain select count(name) from bentest where stamptime>'2007-01-01 00:00:00' and name='one';
--index using 4 characters if used if the order of the columns is switched

+----+-------------+---------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table   | type  | possible_keys | key      | key_len | ref | rows | Extra       |
+----+-------------+---------+-------+---------------+----------+---------+------+------+-------------+
|  1 | SIMPLE      | bentest | range | name_idx      | name_idx | 19      | NULL |    1 | Using where |
+----+-------------+---------+-------+---------------+----------+---------+------+------+-------------+
1 row in set, 2 warnings (0.02 sec)
[9 Aug 2008 6:00] Valeriy Kravchuk
Thank you for a bug report. Verified just as described with 5.0.66a:

C:\Program Files\MySQL\MySQL Server 5.0\bin>mysql -uroot -proot -P3308 test
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 17
Server version: 5.0.66a-enterprise-gpl-nt MySQL Enterprise Server (GPL)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> create table bentest (
    -> id int not null auto_increment,
    -> stamptime timestamp default current_timestamp,
    -> name varchar(10),
    -> primary key (id),
    -> key name_idx (stamptime,name(4))
    -> ) engine=MyISAM;
Query OK, 0 rows affected (0.05 sec)

mysql> insert into bentest (name) values ('one');
Query OK, 1 row affected (0.02 sec)

mysql> insert into bentest (name) values ('two');
Query OK, 1 row affected (0.00 sec)

mysql> insert into bentest (name) values ('three');
Query OK, 1 row affected (0.00 sec)

mysql> insert into bentest (name) values ('four');
Query OK, 1 row affected (0.00 sec)

mysql> insert into bentest (name) values ('five');
Query OK, 1 row affected (0.00 sec)

mysql> insert into bentest (name) values ('six');
Query OK, 1 row affected (0.00 sec)

mysql> insert into bentest (name) values ('seven');
Query OK, 1 row affected (0.00 sec)

mysql> insert into bentest (name) values ('seven2');
Query OK, 1 row affected (0.00 sec)

mysql> insert into bentest (name) values ('seven3');
Query OK, 1 row affected (0.00 sec)

mysql> insert into bentest (name) values ('eight');
Query OK, 1 row affected (0.00 sec)

mysql> explain select count(name) from bentest where stamptime>'2007-01-01 00:00
:00' and
    -> name='one';
+----+-------------+---------+------+---------------+------+---------+------+---
---+-------------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | ro
ws | Extra       |
+----+-------------+---------+------+---------------+------+---------+------+---
---+-------------+
|  1 | SIMPLE      | bentest | ALL  | name_idx      | NULL | NULL    | NULL |
10 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+---
---+-------------+
1 row in set (0.05 sec)

Index can be used:

mysql> explain select count(name) from bentest force index(name_idx) where stamp
time>'2007-01-01 00:00:00' and name='one';
+----+-------------+---------+-------+---------------+----------+---------+-----
-+------+-------------+
| id | select_type | table   | type  | possible_keys | key      | key_len | ref
 | rows | Extra       |
+----+-------------+---------+-------+---------------+----------+---------+-----
-+------+-------------+
|  1 | SIMPLE      | bentest | range | name_idx      | name_idx | 4       | NULL
 |   10 | Using where |
+----+-------------+---------+-------+---------------+----------+---------+-----
-+------+-------------+
1 row in set (0.00 sec)

and it should be used.
[11 Aug 2008 4:59] Valeriy Kravchuk
Same results (index is not used but can and should be used) on 5.1.26-rc.
[10 Jul 2009 23:00] Bugs System
No feedback was provided for this bug for over a month, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".