3534 Sergey Glukhov 2011-10-27
Bug#11747423 32254: INDEX MERGE USED UNNECESSARILY
There was an assumption that quick select is always faster
than ref access for InnoDB tables. But some test cases show
that it's not true for index merge access. In some cases
ref access by compound single key is better than
index merge access by several keys. The fix is to
add a check that INDEX MERGE access is not more expensive
than ref access.
@ mysql-test/r/index_merge_innodb.result
test case
@ mysql-test/t/index_merge_innodb.test
test case
@ sql/sql_select.cc
added a check that INDEX MERGE access is not more expensive
than ref access.
modified:
mysql-test/r/index_merge_innodb.result
mysql-test/t/index_merge_innodb.test
sql/sql_select.cc
3533 Jimmy Yang 2011-10-27
Fix Bug #11755924 - 47764: PARTITIONED INNODB TABLES CAN'T BE MOVED DIRECTLY
FROM WINDOWS TO LINUX
rb://786 approved by Sunny Bains
modified:
storage/innobase/handler/ha_innodb.cc
=== modified file 'mysql-test/r/index_merge_innodb.result'
--- a/mysql-test/r/index_merge_innodb.result 2010-12-02 13:11:15 +0000
+++ b/mysql-test/r/index_merge_innodb.result 2011-10-27 08:40:40 +0000
@@ -273,3 +273,21 @@ id select_type table type possible_keys
1 PRIMARY t1 const PRIMARY PRIMARY 4 const 1 Using index
2 DEPENDENT SUBQUERY t2 index_merge f2,f3 f3,f2 2,5 NULL 1 Using intersect(f3,f2); Using where; Using index
DROP TABLE t1,t2;
+#
+# Bug#11747423 32254: INDEX MERGE USED UNNECESSARILY
+#
+CREATE TABLE t1 (
+id INT NOT NULL PRIMARY KEY,
+id2 INT NOT NULL,
+id3 INT NOT NULL,
+KEY (id2),
+KEY (id3),
+KEY covering_index (id2,id3)
+) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5), (6, 6, 6), (7, 7, 7);
+INSERT INTO t1 SELECT id + 8, id2 + 8, id3 +8 FROM t1;
+INSERT INTO t1 SELECT id + 16, 7, 0 FROM t1;
+EXPLAIN SELECT SQL_NO_CACHE count(*) FROM t1 WHERE id2=7 AND id3=0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref id2,id3,covering_index covering_index 8 const,const 16 Using index
+DROP TABLE t1;
=== modified file 'mysql-test/t/index_merge_innodb.test'
--- a/mysql-test/t/index_merge_innodb.test 2009-10-07 15:37:36 +0000
+++ b/mysql-test/t/index_merge_innodb.test 2011-10-27 08:40:40 +0000
@@ -28,3 +28,24 @@ let $merge_table_support= 0;
--source include/index_merge_2sweeps.inc
--source include/index_merge_ror_cpk.inc
+
+
+--echo #
+--echo # Bug#11747423 32254: INDEX MERGE USED UNNECESSARILY
+--echo #
+CREATE TABLE t1 (
+ id INT NOT NULL PRIMARY KEY,
+ id2 INT NOT NULL,
+ id3 INT NOT NULL,
+ KEY (id2),
+ KEY (id3),
+ KEY covering_index (id2,id3)
+) ENGINE=InnoDB;
+
+INSERT INTO t1 VALUES (0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5), (6, 6, 6), (7, 7, 7);
+INSERT INTO t1 SELECT id + 8, id2 + 8, id3 +8 FROM t1;
+INSERT INTO t1 SELECT id + 16, 7, 0 FROM t1;
+
+EXPLAIN SELECT SQL_NO_CACHE count(*) FROM t1 WHERE id2=7 AND id3=0;
+
+DROP TABLE t1;
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2011-10-27 08:08:46 +0000
+++ b/sql/sql_select.cc 2011-10-27 08:40:40 +0000
@@ -8018,7 +8018,10 @@ best_access_path(JOIN *join,
Don't do a table scan on InnoDB tables, if we can read the used
parts of the row from any of the used index.
This is because table scans uses index and we would not win
- anything by using a table scan.
+ anything by using a table scan. The only exception is INDEX_MERGE
+ quick select. We can not say for sure that INDEX_MERGE quick select
+ is always faster than ref access. So it's necessary to check if
+ ref access is more expensive.
A word for word translation of the below if-statement in sergefp's
understanding: we check if we should use table scan if:
@@ -8058,8 +8061,11 @@ best_access_path(JOIN *join,
goto skip_table_scan;
}
- if (((s->table->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) && //(3)
- !s->table->covering_keys.is_clear_all() && best_key && !s->quick))//(3)
+ if ((s->table->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) && //(3)
+ !s->table->covering_keys.is_clear_all() && best_key && //(3)
+ (!s->quick || //(3)
+ !(s->quick->get_type() == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE && //(3)
+ best > s->quick->read_time))) //(3)
{
trace_access_scan.add_alnum("access_type", s->quick ? "range" : "scan").
add_alnum("cause", "covering_index_better_than_full_scan");
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-trunk branch (sergey.glukhov:3533 to 3534) Bug#11747423 | Sergey Glukhov | 28 Oct |