Bug #34869 Almost 300% regression in index merge intersect performance
Submitted: 27 Feb 2008 2:00 Modified: 20 Jun 2008 3:24
Reporter: Morgan Tocker Email Updates:
Status: Duplicate Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S3 (Non-critical)
Version:5.0 OS:Any
Assigned to: CPU Architecture:Any
Tags: regression

[27 Feb 2008 2:00] Morgan Tocker
Description:
A regression in index merge sometime after 5.0.22 leads to test case execution time go from 0.06 seconds to 0.17 seconds.    Tests were performed on an in memory dataset.  On larger sets of data, this performance drop is even more noticeable.

How to repeat:
In 5.0.22:

11:48 test> SELECT SQL_NO_CACHE count(*) FROM t1 WHERE id_two=7 AND id_three=0 AND id_five=1;
+----------+
| count(*) |
+----------+
|       10 | 
+----------+
1 row in set (0.06 sec)

11:48 test> SELECT SQL_NO_CACHE count(*) FROM t1 FORCE INDEX (covering_index) WHERE id_two=7 AND id_three=0 AND id_five=1;
+----------+
| count(*) |
+----------+
|       10 | 
+----------+
1 row in set (0.07 sec)

In 5.0.52:

11:51 test> SELECT SQL_NO_CACHE count(*) FROM t1 WHERE id_two=7 AND id_three=0 AND id_five=1;
+----------+
| count(*) |
+----------+
|       10 | 
+----------+
1 row in set (0.17 sec)

11:51 test> SELECT SQL_NO_CACHE count(*) FROM t1 FORCE INDEX (covering_index) WHERE id_two=7 AND id_three=0 AND id_five=1;
+----------+
| count(*) |
+----------+
|       10 | 
+----------+
1 row in set (0.07 sec)

11:57 test> EXPLAIN SELECT SQL_NO_CACHE count(*) FROM t1 WHERE id_two=7 AND id_three=0 AND id_five=1;
+----+-------------+-------+-------------+----------------------------------------+-------------------------+---------+------+-------+--------------------------------------------------------------------+
| id | select_type | table | type        | possible_keys                          | key                     | key_len | ref  | rows  | Extra                                                              |
+----+-------------+-------+-------------+----------------------------------------+-------------------------+---------+------+-------+--------------------------------------------------------------------+
|  1 | SIMPLE      | t1    | index_merge | id_two,id_three,id_five,covering_index | id_five,id_two,id_three | 4,4,4   | NULL | 11157 | Using intersect(id_five,id_two,id_three); Using where; Using index | 
+----+-------------+-------+-------------+----------------------------------------+-------------------------+---------+------+-------+--------------------------------------------------------------------+
1 row in set (0.00 sec)

11:57 test> EXPLAIN SELECT SQL_NO_CACHE count(*) FROM t1 FORCE INDEX (covering_index) WHERE id_two=7 AND id_three=0 AND id_five=1;
+----+-------------+-------+------+----------------+----------------+---------+-------------+-------+--------------------------+
| id | select_type | table | type | possible_keys  | key            | key_len | ref         | rows  | Extra                    |
+----+-------------+-------+------+----------------+----------------+---------+-------------+-------+--------------------------+
|  1 | SIMPLE      | t1    | ref  | covering_index | covering_index | 8       | const,const | 79007 | Using where; Using index | 
+----+-------------+-------+------+----------------+----------------+---------+-------------+-------+--------------------------+
1 row in set (0.00 sec)

CREATE TABLE `t1` (
  `id` int(11) NOT NULL,
  `id_two` int(11) NOT NULL,
  `id_three` int(11) NOT NULL,
  `id_four` int(11) NOT NULL,
  `id_five` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `id_two` (`id_two`),
  KEY `id_three` (`id_three`),
  KEY `id_five` (`id_five`),
  KEY `covering_index` (`id_two`,`id_three`,`id_four`,`id_five`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Suggested fix:
Either improve performance, or choose the other index over index merge in the attached test case.
[12 Mar 2008 22:46] Sergey Petrunya
Analysis:

* InnoDB returns the same estimates as before
* range/index_merge optimizer works in the same way as before - it prefers index_merge over range accesses.

The difference is caused by fix for BUG#28189, i.e. by this change:

--- old/sql_select.cc
+++ new/sql_select.cc
@@ -4169,7 +4189,7 @@ best_access_path(JOIN      *join,
       !(s->quick && best_key && s->quick->index == best_key->key &&      // (2)
         best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&// (2)
       !((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) &&      // (3)
-        ! s->table->used_keys.is_clear_all() && best_key) &&             // (3)
+        ! s->table->used_keys.is_clear_all() && best_key && !s->quick) &&// (3)
[13 Mar 2008 21:09] Omer Barnir
triage: are e/r values correct given comment from [12 Mar 23:46] Sergey Petrunia?
        please confirm/change
[20 Jun 2008 3:24] Valeriy Kravchuk
This is a duplicate of bug #32254, it seems.