Bug #68554 | Optimizer wrongly choses covering index over ICP | ||
---|---|---|---|
Submitted: | 3 Mar 2013 16:16 | Modified: | 18 Mar 2013 12:42 |
Reporter: | Jaime Crespo (OCA) | Email Updates: | |
Status: | Verified | Impact on me: | |
Category: | MySQL Server: Optimizer | Severity: | S5 (Performance) |
Version: | 5.6.10 | OS: | Any |
Assigned to: | Assigned Account | CPU Architecture: | Any |
Tags: | condition, covering, ICP, Optimizer, pushdown, USING |
[3 Mar 2013 16:16]
Jaime Crespo
[3 Mar 2013 16:19]
Jaime Crespo
optimizer trace for single-column SELECT
Attachment: trace.json (application/octet-stream, text), 6.16 KiB.
[6 Mar 2013 9:51]
Olav Sandstå
Thanks for a very detailed bug report. Good to see the very positive effect ICP has on the execution time on the first of your queries. About your second query: Your observations are correct. If the optimizer decides that the query can be executed by just reading the index (ie "Using index") then ICP will not be used. And your are right that for this query, using ICP would have improved the execution time due to the high filtering effect of the index condition. The decision to not use ICP for queries that only reads from the index is how this is currently implemented. Some background on why I think this choice was done is that the main goal of ICP is to reduce the number of full records that needs to be read and thus potentially save on IO operations. For the case where only the index needs to be read, the saving will mostly be in reduced CPU usage from not having to return to the server layer to evaluate the condition. This reduction in CPU usage will be highly dependent on the amount of filtering the condition will do. For queries where the condition does not filter out any or just a small fraction of the records, there might even be a small overhead by pushing the condition to the storage engine and evaluate it there. Thus, the current ICP implementation is conservativ and only uses ICP for the case where there is most to gain. Conceptually and coding wise it would be easy to enable ICP for being used also in the case where only the index is needed. To ensure that it would be used only when the likelihood of getting good filtering effect would require to have an estimate on the selectivity of the condition. We do not have this information in the optimizer today. In your example query, we do not have any statistics or heuristics that could tell us that the condition "note like '%Jaime%'" would filter out most records. As you said, ICP is a newly introduced optimizer feature. There are rooms for improvements. Bug reports like the one you have made are good since it gives us feedback with real examples where extending the use of ICP would benefit the performance. About the "rows" estimate for explain when using ICP: This is the estimate that the optimizer has on how many rows that ref access on "role_id = 1" will produce. The optimizer does not at the moment have any estimate or statistics on how many of these that will be filtered out by the "note like '%Jaime%'" condition. Thus, it is hard to take the filtering effect of using ICP into account in the "rows" estimate. And I am not sure it should take it into account either. Using ICP will reduce the number of full records that need to be read, but still the index entries for all these records will be read and evaluated.
[18 Mar 2013 12:49]
Olav Sandstå
I have marked this as a "Feature request" to enable Index condition pushdown to be used for "index only" queries.
[25 Mar 2016 3:30]
Jervin R
I hope this can implemented soon, on small table the performance difference is negligible but on large tables this is more problematic and non-deterministic performance. I've created another test case on 5.6.29. mysql [localhost] {msandbox} (test) > create table t (id int unsigned not null auto_increment primary key, x int not null default 0, key (x, id)) engine=innodb; Query OK, 0 rows affected (0.03 sec) mysql [localhost] {msandbox} (test) > insert into t (x) values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (10), (7), (13), (15), (16); Query OK, 15 rows affected (0.01 sec) Records: 15 Duplicates: 0 Warnings: 0 mysql [localhost] {msandbox} (test) > insert into t (x) select x from t; Query OK, 15 rows affected (0.01 sec) Records: 15 Duplicates: 0 Warnings: 0 ... mysql [localhost] {msandbox} (test) > insert into t (x) select x from t; Query OK, 491520 rows affected (1.90 sec) Records: 491520 Duplicates: 0 Warnings: 0 mysql [localhost] {msandbox} (test) > explain select * from t where x = 13 and id between 245760 and 245762; +----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+ | 1 | SIMPLE | t | ref | PRIMARY,x | x | 4 | const | 1 | Using where; Using index | +----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+ 1 row in set (0.00 sec) mysql [localhost] {msandbox} (test) > explain select * from t where x = 13 and id between 245760 and 245761; +----+-------------+-------+-------+---------------+------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+------+---------+------+------+--------------------------+ | 1 | SIMPLE | t | range | PRIMARY,x | x | 8 | NULL | 1 | Using where; Using index | +----+-------------+-------+-------+---------------+------+---------+------+------+--------------------------+ 1 row in set (0.00 sec) mysql [localhost] {msandbox} (test) > explain select * from t where x = 13 and id between 245760 and 245762; +----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+ | 1 | SIMPLE | t | ref | PRIMARY,x | x | 4 | const | 1 | Using where; Using index | +----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+ 1 row in set (0.00 sec)
[25 Mar 2016 4:04]
Jervin R
I realized my test case is a little different so I created a new bug http://bugs.mysql.com/bug.php?id=80856
[14 Mar 2022 16:43]
Jean-François Gagné
Related: Bug#104659.