summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsergefp@mysql.com <>2006-01-12 11:55:34 +0300
committersergefp@mysql.com <>2006-01-12 11:55:34 +0300
commit40b7fab55d4d37fcafbe6214ac4c3b311599da03 (patch)
tree5fdc251d88ba169d33c1c81e46a2bb36147512b7
parent00936e2777595035b2db37a061daad0a39c57694 (diff)
parentaa00d65ead2b3ac14154a141497f25f1df6a000a (diff)
downloadmariadb-git-40b7fab55d4d37fcafbe6214ac4c3b311599da03.tar.gz
Merge spetrunia@bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/psergey/mysql-5.0-bug16166-r2
-rw-r--r--mysql-test/r/index_merge.result18
-rw-r--r--mysql-test/t/index_merge.test30
-rw-r--r--sql/sql_select.cc35
3 files changed, 76 insertions, 7 deletions
diff --git a/mysql-test/r/index_merge.result b/mysql-test/r/index_merge.result
index d039d5a04c9..db87253e19a 100644
--- a/mysql-test/r/index_merge.result
+++ b/mysql-test/r/index_merge.result
@@ -384,3 +384,21 @@ max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.ke
8186
set join_buffer_size= @save_join_buffer_size;
drop table t0, t1, t2, t3, t4;
+CREATE TABLE t1 (
+cola char(3) not null, colb char(3) not null, filler char(200),
+key(cola), key(colb)
+);
+INSERT INTO t1 VALUES ('foo','bar', 'ZZ'),('fuz','baz', 'ZZ');
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+select count(*) from t1;
+count(*)
+8704
+explain select * from t1 WHERE cola = 'foo' AND colb = 'bar';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL 24 Using intersect(cola,colb); Using where
+explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'bar';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL 24 Using intersect(cola,colb); Using where
+drop table t1;
diff --git a/mysql-test/t/index_merge.test b/mysql-test/t/index_merge.test
index 42175a757c2..10512902409 100644
--- a/mysql-test/t/index_merge.test
+++ b/mysql-test/t/index_merge.test
@@ -327,3 +327,33 @@ set join_buffer_size= @save_join_buffer_size;
drop table t0, t1, t2, t3, t4;
+# BUG#16166
+CREATE TABLE t1 (
+ cola char(3) not null, colb char(3) not null, filler char(200),
+ key(cola), key(colb)
+);
+INSERT INTO t1 VALUES ('foo','bar', 'ZZ'),('fuz','baz', 'ZZ');
+
+--disable_query_log
+let $1=9;
+while ($1)
+{
+ eval INSERT INTO t1 SELECT * from t1 WHERE cola = 'foo';
+ dec $1;
+}
+
+let $1=13;
+while ($1)
+{
+ eval INSERT INTO t1 SELECT * from t1 WHERE cola <> 'foo';
+ dec $1;
+}
+
+--enable_query_log
+
+OPTIMIZE TABLE t1;
+select count(*) from t1;
+explain select * from t1 WHERE cola = 'foo' AND colb = 'bar';
+explain select * from t1 force index(cola,colb) WHERE cola = 'foo' AND colb = 'bar';
+drop table t1;
+
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index c282a5bd42c..e8f2cb2c6a0 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -3471,13 +3471,32 @@ best_access_path(JOIN *join,
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.
+
+ A word for word translation of the below if-statement in psergey's
+ understanding: we check if we should use table scan if:
+ (1) The found 'ref' access produces more records than a table scan
+ (or index scan, or quick select), or 'ref' is more expensive than
+ any of them.
+ (2) This doesn't hold: the best way to perform table scan is to to perform
+ 'range' access using index IDX, and the best way to perform 'ref'
+ access is to use the same index IDX, with the same or more key parts.
+ (note: it is not clear how this rule is/should be extended to
+ index_merge quick selects)
+ (3) See above note about InnoDB.
+ (4) NOT ("FORCE INDEX(...)" is used for table and there is 'ref' access
+ path, but there is no quick select)
+ If the condition in the above brackets holds, then the only possible
+ "table scan" access method is ALL/index (there is no quick select).
+ Since we have a 'ref' access path, and FORCE INDEX instructs us to
+ choose it over ALL/index, there is no need to consider a full table
+ scan.
*/
- if ((records >= s->found_records || best > s->read_time) &&
- !(s->quick && best_key && s->quick->index == best_key->key &&
- best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&
- !((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) &&
- ! s->table->used_keys.is_clear_all() && best_key) &&
- !(s->table->force_index && best_key))
+ if ((records >= s->found_records || best > s->read_time) && // (1)
+ !(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->force_index && best_key && !s->quick)) // (4)
{ // Check full join
ha_rows rnd_records= s->found_records;
/*
@@ -4460,13 +4479,15 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
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.
+ (see comment in best_access_path() for more details on the below
+ condition)
*/
if ((records >= s->found_records || best > s->read_time) &&
!(s->quick && best_key && s->quick->index == best_key->key &&
best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&
!((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) &&
! s->table->used_keys.is_clear_all() && best_key) &&
- !(s->table->force_index && best_key))
+ !(s->table->force_index && best_key && !s->quick))
{ // Check full join
ha_rows rnd_records= s->found_records;
/*