Description:
MySQL does not use the functional index on the function LOG10
How to repeat:
mysql> CREATE TABLE expdata ( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> value FLOAT,
-> INDEX log10_fi ((log10(value)))
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> INSERT INTO expdata (value) VALUES (.01),(.1),(1),(10),(100);
Query OK, 5 rows affected (0.01 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> SELECT id, value, log10(value) FROM expdata;
+----+-------+--------------------+
| id | value | log10(value) |
+----+-------+--------------------+
| 1 | 0.01 | -2.000000009707238 |
| 2 | 0.1 | -0.999999993528508 |
| 3 | 1 | 0 |
| 4 | 10 | 1 |
| 5 | 100 | 2 |
+----+-------+--------------------+
5 rows in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM expdata WHERE log10(value) < 0;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | expdata | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 100.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
Note (Code 1003): /* select#1 */ select `cookbook`.`expdata`.`id` AS `id`,`cookbook`.`expdata`.`value` AS `value` from `cookbook`.`expdata` where (log10(`cookbook`.`expdata`.`value`) < 0)
-- OK, maybe it complains about range? What about equality?
mysql> EXPLAIN SELECT * FROM expdata WHERE log10(value) = 0;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | expdata | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 100.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
Note (Code 1003): /* select#1 */ select `cookbook`.`expdata`.`id` AS `id`,`cookbook`.`expdata`.`value` AS `value` from `cookbook`.`expdata` where (log10(`cookbook`.`expdata`.`value`) = 0)
-- Maybe the reason is that our column defined as FLOAT that makes any function not deterministic?
-- Let's try with DECIMAL for which LOG10 will always generate deterministic values
mysql> DROP TABLE expdata;
Query OK, 0 rows affected (0.02 sec)
mysql> CREATE TABLE expdata ( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> value DECIMAL (10, 2),
-> INDEX log10_fi ((log10(value)))
-> );
Query OK, 0 rows affected (0.03 sec)
mysql>
mysql> INSERT INTO expdata (value) VALUES (.01),(.1),(1),(10),(100);
Query OK, 5 rows affected (0.01 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> SELECT id, value, log10(value) FROM expdata;
+----+--------+--------------+
| id | value | log10(value) |
+----+--------+--------------+
| 1 | 0.01 | -2 |
| 2 | 0.10 | -1 |
| 3 | 1.00 | 0 |
| 4 | 10.00 | 1 |
| 5 | 100.00 | 2 |
+----+--------+--------------+
5 rows in set (0.00 sec)
mysql>
mysql> EXPLAIN SELECT * FROM expdata WHERE log10(value) < 0;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | expdata | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 100.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
Note (Code 1003): /* select#1 */ select `cookbook`.`expdata`.`id` AS `id`,`cookbook`.`expdata`.`value` AS `value` from `cookbook`.`expdata` where (log10(`cookbook`.`expdata`.`value`) < 0)
mysql> EXPLAIN SELECT * FROM expdata WHERE log10(value) = 0;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | expdata | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 100.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
Note (Code 1003): /* select#1 */ select `cookbook`.`expdata`.`id` AS `id`,`cookbook`.`expdata`.`value` AS `value` from `cookbook`.`expdata` where (log10(`cookbook`.`expdata`.`value`) = 0)
-- Still no luck!
-- What about PostgreSQL?
postgres=# create table expdata(id int, value float);
CREATE TABLE
postgres=# CREATE INDEX test_log10_fi on expdata (log10(value));
CREATE INDEX
postgres=# insert into expdata values(1,.01),(2,.1),(3,1),(4,10),(5,100);
INSERT 0 5
postgres=# explain SELECT * FROM expdata WHERE log10(value) < 0;
QUERY PLAN
------------------------------------------------------------------------------
Bitmap Heap Scan on expdata (cost=9.42..29.62 rows=680 width=12)
Recheck Cond: (log10(value) < '0'::double precision)
-> Bitmap Index Scan on test_log10_fi (cost=0.00..9.25 rows=680 width=0)
Index Cond: (log10(value) < '0'::double precision)
(4 rows)
postgres=# explain SELECT * FROM expdata WHERE log10(value) = 0;
QUERY PLAN
-----------------------------------------------------------------------------
Bitmap Heap Scan on expdata (cost=4.23..14.81 rows=10 width=12)
Recheck Cond: (log10(value) = '0'::double precision)
-> Bitmap Index Scan on test_log10_fi (cost=0.00..4.23 rows=10 width=0)
Index Cond: (log10(value) = '0'::double precision)
(4 rows)
It perfectly works!
Suggested fix:
Use functional indexes on LOG10. Probably test all built-in deterministic functions?
Description: MySQL does not use the functional index on the function LOG10 How to repeat: mysql> CREATE TABLE expdata ( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, -> value FLOAT, -> INDEX log10_fi ((log10(value))) -> ); Query OK, 0 rows affected (0.02 sec) mysql> INSERT INTO expdata (value) VALUES (.01),(.1),(1),(10),(100); Query OK, 5 rows affected (0.01 sec) Records: 5 Duplicates: 0 Warnings: 0 mysql> SELECT id, value, log10(value) FROM expdata; +----+-------+--------------------+ | id | value | log10(value) | +----+-------+--------------------+ | 1 | 0.01 | -2.000000009707238 | | 2 | 0.1 | -0.999999993528508 | | 3 | 1 | 0 | | 4 | 10 | 1 | | 5 | 100 | 2 | +----+-------+--------------------+ 5 rows in set (0.00 sec) mysql> EXPLAIN SELECT * FROM expdata WHERE log10(value) < 0; +----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | expdata | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 100.00 | Using where | +----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) Note (Code 1003): /* select#1 */ select `cookbook`.`expdata`.`id` AS `id`,`cookbook`.`expdata`.`value` AS `value` from `cookbook`.`expdata` where (log10(`cookbook`.`expdata`.`value`) < 0) -- OK, maybe it complains about range? What about equality? mysql> EXPLAIN SELECT * FROM expdata WHERE log10(value) = 0; +----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | expdata | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 100.00 | Using where | +----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) Note (Code 1003): /* select#1 */ select `cookbook`.`expdata`.`id` AS `id`,`cookbook`.`expdata`.`value` AS `value` from `cookbook`.`expdata` where (log10(`cookbook`.`expdata`.`value`) = 0) -- Maybe the reason is that our column defined as FLOAT that makes any function not deterministic? -- Let's try with DECIMAL for which LOG10 will always generate deterministic values mysql> DROP TABLE expdata; Query OK, 0 rows affected (0.02 sec) mysql> CREATE TABLE expdata ( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, -> value DECIMAL (10, 2), -> INDEX log10_fi ((log10(value))) -> ); Query OK, 0 rows affected (0.03 sec) mysql> mysql> INSERT INTO expdata (value) VALUES (.01),(.1),(1),(10),(100); Query OK, 5 rows affected (0.01 sec) Records: 5 Duplicates: 0 Warnings: 0 mysql> SELECT id, value, log10(value) FROM expdata; +----+--------+--------------+ | id | value | log10(value) | +----+--------+--------------+ | 1 | 0.01 | -2 | | 2 | 0.10 | -1 | | 3 | 1.00 | 0 | | 4 | 10.00 | 1 | | 5 | 100.00 | 2 | +----+--------+--------------+ 5 rows in set (0.00 sec) mysql> mysql> EXPLAIN SELECT * FROM expdata WHERE log10(value) < 0; +----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | expdata | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 100.00 | Using where | +----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) Note (Code 1003): /* select#1 */ select `cookbook`.`expdata`.`id` AS `id`,`cookbook`.`expdata`.`value` AS `value` from `cookbook`.`expdata` where (log10(`cookbook`.`expdata`.`value`) < 0) mysql> EXPLAIN SELECT * FROM expdata WHERE log10(value) = 0; +----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | expdata | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 100.00 | Using where | +----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) Note (Code 1003): /* select#1 */ select `cookbook`.`expdata`.`id` AS `id`,`cookbook`.`expdata`.`value` AS `value` from `cookbook`.`expdata` where (log10(`cookbook`.`expdata`.`value`) = 0) -- Still no luck! -- What about PostgreSQL? postgres=# create table expdata(id int, value float); CREATE TABLE postgres=# CREATE INDEX test_log10_fi on expdata (log10(value)); CREATE INDEX postgres=# insert into expdata values(1,.01),(2,.1),(3,1),(4,10),(5,100); INSERT 0 5 postgres=# explain SELECT * FROM expdata WHERE log10(value) < 0; QUERY PLAN ------------------------------------------------------------------------------ Bitmap Heap Scan on expdata (cost=9.42..29.62 rows=680 width=12) Recheck Cond: (log10(value) < '0'::double precision) -> Bitmap Index Scan on test_log10_fi (cost=0.00..9.25 rows=680 width=0) Index Cond: (log10(value) < '0'::double precision) (4 rows) postgres=# explain SELECT * FROM expdata WHERE log10(value) = 0; QUERY PLAN ----------------------------------------------------------------------------- Bitmap Heap Scan on expdata (cost=4.23..14.81 rows=10 width=12) Recheck Cond: (log10(value) = '0'::double precision) -> Bitmap Index Scan on test_log10_fi (cost=0.00..4.23 rows=10 width=0) Index Cond: (log10(value) = '0'::double precision) (4 rows) It perfectly works! Suggested fix: Use functional indexes on LOG10. Probably test all built-in deterministic functions?