Bug #58190 | BETWEEN no longer uses indexes for date or datetime fields | ||
---|---|---|---|
Submitted: | 15 Nov 2010 3:13 | Modified: | 11 Dec 2010 17:23 |
Reporter: | chris valaas | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: Charsets | Severity: | S2 (Serious) |
Version: | 5.5.7, 5.5.8 | OS: | Any (Solaris, Mac OS X, Linux) |
Assigned to: | Alexander Barkov | CPU Architecture: | Any |
Tags: | regression |
[15 Nov 2010 3:13]
chris valaas
[15 Nov 2010 5:08]
Valeriy Kravchuk
Indeed, index is not used, even if table is MyISAM (so it is not about statistics probably): macbook-pro:5.5 openxs$ bin/mysql -A -uroot test Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 Server version: 5.5.7-rc-debug Source distribution Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> CREATE TABLE `date_index_test` ( -> `id` int(11) DEFAULT NULL, -> `date_column` date DEFAULT NULL, -> KEY `date_column` (`date_column`) -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.19 sec) mysql> insert into date_index_test values (1,'2010-09-01'),(2,'2010-10-01'); Query OK, 2 rows affected (0.03 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> explain select * from date_index_test where date_column between '2010-09-01' and -> '2010-10-01'; +----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | date_index_test | ALL | date_column | NULL | NULL | NULL | 2 | Using where | +----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+ 1 row in set (0.01 sec) mysql> explain select * from date_index_test where date_column >= '2010-09-01' and -> date_column <='2010-10-01'; +----+-------------+-----------------+-------+---------------+-------------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------------+-------+---------------+-------------+---------+------+------+-------------+ | 1 | SIMPLE | date_index_test | range | date_column | date_column | 4 | NULL | 2 | Using where | +----+-------------+-----------------+-------+---------------+-------------+---------+------+------+-------------+ 1 row in set (0.36 sec) mysql> alter table date_index_test engine=MyISAM; Query OK, 2 rows affected (0.49 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> explain select * from date_index_test where date_column between '2010-09-01' and '2010-10-01'; +----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | date_index_test | ALL | date_column | NULL | NULL | NULL | 2 | Using where | +----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+ 1 row in set (0.00 sec) But for a range that includes all rows in the table it may be even not bad. Had you tried to add more rows?
[15 Nov 2010 5:34]
chris valaas
We have tables with several million rows and selects using BETWEEN on just a tiny portion still do not use the index. This seems have have started in 5.5.*.
[15 Nov 2010 7:09]
Valeriy Kravchuk
Indeed, it works as expected in 5.1.52: mysql> select version(); +------------------+ | version() | +------------------+ | 5.1.52-community | +------------------+ 1 row in set (0.01 sec) mysql> CREATE TABLE `date_index_test` ( -> `id` int(11) DEFAULT NULL, -> `date_column` date DEFAULT NULL, -> KEY `date_column` (`date_column`) -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ERROR 2006 (HY000): MySQL server has gone away No connection. Trying to reconnect... Connection id: 16 Current database: test Query OK, 0 rows affected (0.66 sec) mysql> insert into date_index_test values (1,'2010-09-01'),(2,'2010-10-01'); Query OK, 2 rows affected (0.03 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> explain select * from date_index_test where date_column between '2010-09- 01' and -> '2010-10-01'; +----+-------------+-----------------+-------+---------------+-------------+---- -----+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key _len | ref | rows | Extra | +----+-------------+-----------------+-------+---------------+-------------+---- -----+------+------+-------------+ | 1 | SIMPLE | date_index_test | range | date_column | date_column | 4 | NULL | 1 | Using where | +----+-------------+-----------------+-------+---------------+-------------+---- -----+------+------+-------------+ 1 row in set (0.08 sec)
[18 Nov 2010 9:25]
Valeriy Kravchuk
Same problem with current mysql-5.5-security tree on Ubuntu 10.04: openxs@ubuntu:~/dbs/5.5-sec$ bin/mysql --no-defaults -uroot test Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.5.8-rc Source distribution Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> CREATE TABLE `date_index_test` ( -> `id` int(11) DEFAULT NULL, -> `date_column` date DEFAULT NULL, -> KEY `date_column` (`date_column`) -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.10 sec) mysql> insert into date_index_test values (1,'2010-09-01'),(2,'2010-10-01'); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> explain select * from date_index_test where date_column between '2010-09-01' and -> '2010-10-01'; +----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | date_index_test | ALL | date_column | NULL | NULL | NULL | 2 | Using where | +----+-------------+-----------------+------+---------------+------+---------+------+------+-------------+ 1 row in set (0.00 sec) mysql> explain select * from date_index_test where date_column >= '2010-09-01' and -> date_column <='2010-10-01'; +----+-------------+-----------------+-------+---------------+-------------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------------+-------+---------------+-------------+---------+------+------+-------------+ | 1 | SIMPLE | date_index_test | range | date_column | date_column | 4 | NULL | 2 | Using where | +----+-------------+-----------------+-------+---------------+-------------+---------+------+------+-------------+ 1 row in set (0.00 sec)
[18 Nov 2010 11:20]
Øystein Grøvlen
This seems to be a character set issue. If I set default character set to latin1, index is used. That is, mysql> set NAMES latin1; Query OK, 0 rows affected (0.00 sec) mysql> explain select * from date_index_test where date_column between '2010-09-01' and '2010-10-01'; +----+-------------+-----------------+-------+---------------+-------------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------------+-------+---------------+-------------+---------+------+------+-------------+ | 1 | SIMPLE | date_index_test | range | date_column | date_column | 4 | NULL | 1 | Using where | +----+-------------+-----------------+-------+---------------+-------------+---------+------+------+-------------+
[18 Nov 2010 12:31]
Øystein Grøvlen
It is decided that index cannot be used because the following test in get_mm_leaf() is true: ((Field_str*)field)->charset() != conf_func->compare_collation() LHS is latin1, RHS is UTF8
[19 Nov 2010 15:05]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/124480 3137 Alexander Barkov 2010-11-19 Bug#58190 BETWEEN no longer uses indexes for date or datetime fields Regression introduced by WL#2649. Problem: queries with date/datetime columns did not use indexes: set names non_latin1_charset; select * from date_index_test where date_column between '2010-09-01' and '2010-10-01'; before WL#2649 indexes worked fine because charset of date/datetime columns was BINARY which always won. Fix: testing that collation of the operation matches collation of the field is only needed in case of "real" string data types. For DATE, DATETIME it's not needed. Note, the problem remains with UCS2, UTF16, UTF32 (index is not used). But this is not a regressions, as in 5.1 comparison between DATE/DATETIME and UCS2/UTF16/UTF32 did not work at all (always returned FALSE). @ mysql-test/include/ctype_numconv.inc @ mysql-test/r/ctype_binary.result @ mysql-test/r/ctype_cp1251.result @ mysql-test/r/ctype_latin1.result @ mysql-test/r/ctype_ucs.result @ mysql-test/r/ctype_utf8.result Adding tests @ sql/field.h Adding new method to distinguish between "real string" types like CHAR, VARCHAR, TEXT, and "almost string" types, like DATE, DATETIME. @ sql/opt_range.cc Checking collation only for "real string" types.
[19 Nov 2010 16:40]
Alexander Barkov
The second part of this problem is reported as a separate bug: Bug#58329 Bug#58190 BETWEEN does not use indexes for date or datetime fields for UCS2+ (which is not a regression)
[19 Nov 2010 17:33]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/124502 3138 Alexander Barkov 2010-11-19 Bug#58190 BETWEEN no longer uses indexes for date or datetime fields Regression introduced by WL#2649. Problem: queries with date/datetime columns did not use indexes: set names non_latin1_charset; select * from date_index_test where date_column between '2010-09-01' and '2010-10-01'; before WL#2649 indexes worked fine because charset of date/datetime columns was BINARY which always won. Fix: testing that collation of the operation matches collation of the field is only needed in case of "real" string data types. For DATE, DATETIME it's not needed. @ mysql-test/include/ctype_numconv.inc @ mysql-test/r/ctype_binary.result @ mysql-test/r/ctype_cp1251.result @ mysql-test/r/ctype_latin1.result @ mysql-test/r/ctype_ucs.result @ mysql-test/r/ctype_utf8.result Adding tests @ sql/field.h Adding new method Field_str::match_collation_to_optimize_range() for use in opt_range.cc to distinguish between "real string" types like CHAR, VARCHAR, TEXT (Field_string, Field_varstring, Field_blob) and "almost string" types DATE, TIME, DATETIME (Field_newdate, Field_datetime, Field_time, Field_timestamp) @ sql/opt_range.cc Using new method instead of checking result_type() against STRING result. Note: Another part of this problem (which is not regression) is submitted separately (see bug##58329).
[19 Nov 2010 19:53]
Alexander Barkov
Pushed into mysql-5.5-bugteam [5.5.8] Pushed into mysql-trunk-bugteam [5.6.1-m5]
[5 Dec 2010 12:42]
Bugs System
Pushed into mysql-trunk 5.6.1 (revid:alexander.nozdrin@oracle.com-20101205122447-6x94l4fmslpbttxj) (version source revid:alexander.nozdrin@oracle.com-20101205122447-6x94l4fmslpbttxj) (merge vers: 5.6.1) (pib:23)
[11 Dec 2010 17:23]
Paul DuBois
Noted in 5.5.8 changelog. BETWEEN did not use indexes for DATE or DATETIME columns.
[16 Dec 2010 22:33]
Bugs System
Pushed into mysql-5.5 5.5.9 (revid:jonathan.perkin@oracle.com-20101216101358-fyzr1epq95a3yett) (version source revid:jonathan.perkin@oracle.com-20101216101358-fyzr1epq95a3yett) (merge vers: 5.5.9) (pib:24)