List:Commits« Previous MessageNext Message »
From:igor Date:January 31 2007 4:30am
Subject:bk commit into 5.0 tree (igor:1.2392) BUG#25407
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of igor. When igor does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-01-30 19:30:08-08:00, igor@stripped +5 -0
  Fixed bug #25407.
  The bug coud cause choosing a sub-optimal execution plan for a single-table query
  if a unuque index with many null keys were defined for the table. 
  It happened because the code of the check_quick_keys function made an assumption
  that any key may occur in an unique index only once. Yet this is not true for keys
  with nulls that may have multiple occurrences in the index.

  mysql-test/r/null_key.result@stripped, 2007-01-30 19:30:06-08:00, igor@stripped +1 -1
    Fixed bug #25407
    Adjusted result after the fix.

  mysql-test/r/ps_5merge.result@stripped, 2007-01-30 19:30:06-08:00, igor@stripped +2 -2
    Fixed bug #25407
    Adjusted result after the fix.

  mysql-test/r/select.result@stripped, 2007-01-30 19:30:06-08:00, igor@stripped +81 -0
    Added a test case for bug #25407.

  mysql-test/t/select.test@stripped, 2007-01-30 19:30:06-08:00, igor@stripped +71 -0
    Added a test case for bug #25407.

  sql/opt_range.cc@stripped, 2007-01-30 19:30:06-08:00, igor@stripped +2 -1
    Fixed bug #25407.
    The bug could cause choosing a sub-optimal execution plan for a single-table query
    if a unique index with many null keys were defined for the table. 
    It happened because the code of the check_quick_keys function made an assumption
    that any key may occur in an unique index only once. Yet this is not true for keys
    with nulls that may have multiple occurrences in the index.
    

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	igor
# Host:	olga.mysql.com
# Root:	/home/igor/dev-opt/mysql-5.0-opt-bug25407

--- 1.237/sql/opt_range.cc	2007-01-30 19:30:15 -08:00
+++ 1.238/sql/opt_range.cc	2007-01-30 19:30:15 -08:00
@@ -5790,7 +5790,8 @@
       (param->table->key_info[keynr].flags & (HA_NOSAME | HA_END_SPACE_KEY)) ==
       HA_NOSAME &&
       min_key_length == max_key_length &&
-      !memcmp(param->min_key,param->max_key,min_key_length))
+      !memcmp(param->min_key,param->max_key,min_key_length) &&
+      key_tree->left != &null_element)
   {
     tmp=1;					// Max one record
     param->n_ranges++;

--- 1.44/mysql-test/r/ps_5merge.result	2007-01-30 19:30:15 -08:00
+++ 1.45/mysql-test/r/ps_5merge.result	2007-01-30 19:30:15 -08:00
@@ -1535,8 +1535,8 @@
 execute stmt1 using @arg00, @arg01, @arg02, @arg03 ;
 select a,b from t1 where a in (@arg00,@arg02) ;
 a	b
-81	8-1
 82	8-2
+81	8-1
 set @arg00=9 ;
 set @arg01='nine' ;
 prepare stmt1 from 'insert into t1 set a=?, b=? ';
@@ -4549,8 +4549,8 @@
 execute stmt1 using @arg00, @arg01, @arg02, @arg03 ;
 select a,b from t1 where a in (@arg00,@arg02) ;
 a	b
-81	8-1
 82	8-2
+81	8-1
 set @arg00=9 ;
 set @arg01='nine' ;
 prepare stmt1 from 'insert into t1 set a=?, b=? ';

--- 1.36/mysql-test/r/null_key.result	2007-01-30 19:30:15 -08:00
+++ 1.37/mysql-test/r/null_key.result	2007-01-30 19:30:15 -08:00
@@ -258,7 +258,7 @@
 INSERT INTO t2 VALUES
(1,NULL),(2,NULL),(3,1),(4,2),(5,NULL),(6,NULL),(7,3),(8,4),(9,NULL),(10,NULL);
 explain select id from t1 where uniq_id is null;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	SIMPLE	t1	ref	idx1	idx1	5	const	1	Using where
+1	SIMPLE	t1	ref	idx1	idx1	5	const	5	Using where
 explain select id from t1 where uniq_id =1;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	const	idx1	idx1	5	const	1	

--- 1.146/mysql-test/r/select.result	2007-01-30 19:30:15 -08:00
+++ 1.147/mysql-test/r/select.result	2007-01-30 19:30:15 -08:00
@@ -3642,3 +3642,84 @@
 SELECT * FROM t1 LIMIT 2, -1;
 ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to
your MySQL server version for the right syntax to use near '-1' at line 1
 DROP TABLE t1;
+CREATE TABLE t1 (
+ID_with_null int NULL,
+ID_better int NOT NULL,
+INDEX idx1 (ID_with_null),
+INDEX idx2 (ID_better)
+);
+INSERT INTO t1 VALUES (1,1), (2,1), (null,3), (null,3), (null,3), (null,3);
+INSERT INTO t1 SELECT * FROM t1 WHERE ID_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID_with_null IS NULL;
+SELECT COUNT(*) FROM t1 WHERE ID_with_null IS NULL;
+COUNT(*)
+128
+SELECT COUNT(*) FROM t1 WHERE ID_better=1;
+COUNT(*)
+2
+EXPLAIN SELECT * FROM t1 WHERE ID_better=1 AND ID_with_null IS NULL;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	ref	idx1,idx2	idx2	4	const	1	Using where
+DROP INDEX idx1 ON t1;
+CREATE UNIQUE INDEX idx1 ON t1(ID_with_null);
+EXPLAIN SELECT * FROM t1 WHERE ID_better=1 AND ID_with_null IS NULL;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	ref	idx1,idx2	idx2	4	const	1	Using where
+DROP TABLE t1;
+CREATE TABLE t1 (
+ID1_with_null int NULL,
+ID2_with_null int NULL,
+ID_better int NOT NULL,
+INDEX idx1 (ID1_with_null, ID2_with_null),
+INDEX idx2 (ID_better)
+);
+INSERT INTO t1 VALUES (1,1,1), (2,2,1), (3,null,3), (null,3,3), (null,null,3),
+(3,null,3), (null,3,3), (null,null,3), (3,null,3), (null,3,3), (null,null,3);
+INSERT INTO t1 SELECT * FROM t1 WHERE ID1_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID2_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID1_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID2_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID1_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID2_with_null IS NULL;
+SELECT COUNT(*) FROM t1 WHERE ID1_with_null IS NULL AND ID2_with_null=3;
+COUNT(*)
+24
+SELECT COUNT(*) FROM t1 WHERE ID1_with_null=3 AND ID2_with_null IS NULL;
+COUNT(*)
+24
+SELECT COUNT(*) FROM t1 WHERE ID1_with_null IS NULL AND ID2_with_null IS NULL;
+COUNT(*)
+192
+SELECT COUNT(*) FROM t1 WHERE ID_better=1;
+COUNT(*)
+2
+EXPLAIN SELECT * FROM t1
+WHERE ID_better=1 AND ID1_with_null IS NULL AND ID2_with_null=3 ;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	ref	idx1,idx2	idx2	4	const	1	Using where
+EXPLAIN SELECT * FROM t1
+WHERE ID_better=1 AND ID1_with_null=3 AND ID2_with_null=3 IS NULL ;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	ref	idx1,idx2	idx2	4	const	1	Using where
+EXPLAIN SELECT * FROM t1
+WHERE ID_better=1 AND ID1_with_null IS NULL AND ID2_with_null IS NULL;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	ref	idx1,idx2	idx2	4	const	1	Using where
+DROP INDEX idx1 ON t1;
+CREATE UNIQUE INDEX idx1 ON t1(ID1_with_null,ID2_with_null);
+EXPLAIN SELECT * FROM t1
+WHERE ID_better=1 AND ID1_with_null IS NULL AND ID2_with_null=3 ;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	ref	idx1,idx2	idx2	4	const	1	Using where
+EXPLAIN SELECT * FROM t1
+WHERE ID_better=1 AND ID1_with_null=3 AND ID2_with_null IS NULL ;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	ref	idx1,idx2	idx2	4	const	1	Using where
+EXPLAIN SELECT * FROM t1
+WHERE ID_better=1 AND ID1_with_null IS NULL AND ID2_with_null IS NULL;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	ref	idx1,idx2	idx2	4	const	1	Using where
+DROP TABLE t1;

--- 1.120/mysql-test/t/select.test	2007-01-30 19:30:15 -08:00
+++ 1.121/mysql-test/t/select.test	2007-01-30 19:30:15 -08:00
@@ -3133,3 +3133,74 @@
 
 DROP TABLE t1;
 
+#
+# 25407: wrong estimate of NULL keys for unique indexes
+#
+
+CREATE TABLE t1 (
+  ID_with_null int NULL,
+  ID_better int NOT NULL,
+  INDEX idx1 (ID_with_null),
+  INDEX idx2 (ID_better)
+);
+
+INSERT INTO t1 VALUES (1,1), (2,1), (null,3), (null,3), (null,3), (null,3);
+INSERT INTO t1 SELECT * FROM t1 WHERE ID_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID_with_null IS NULL;
+
+SELECT COUNT(*) FROM t1 WHERE ID_with_null IS NULL;
+SELECT COUNT(*) FROM t1 WHERE ID_better=1;
+
+EXPLAIN SELECT * FROM t1 WHERE ID_better=1 AND ID_with_null IS NULL;
+
+DROP INDEX idx1 ON t1;
+CREATE UNIQUE INDEX idx1 ON t1(ID_with_null);
+
+EXPLAIN SELECT * FROM t1 WHERE ID_better=1 AND ID_with_null IS NULL;
+
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+  ID1_with_null int NULL,
+  ID2_with_null int NULL,
+  ID_better int NOT NULL,
+  INDEX idx1 (ID1_with_null, ID2_with_null),
+  INDEX idx2 (ID_better)
+);
+
+INSERT INTO t1 VALUES (1,1,1), (2,2,1), (3,null,3), (null,3,3), (null,null,3),
+  (3,null,3), (null,3,3), (null,null,3), (3,null,3), (null,3,3), (null,null,3);
+
+INSERT INTO t1 SELECT * FROM t1 WHERE ID1_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID2_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID1_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID2_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID1_with_null IS NULL;
+INSERT INTO t1 SELECT * FROM t1 WHERE ID2_with_null IS NULL;
+
+SELECT COUNT(*) FROM t1 WHERE ID1_with_null IS NULL AND ID2_with_null=3;
+SELECT COUNT(*) FROM t1 WHERE ID1_with_null=3 AND ID2_with_null IS NULL;
+SELECT COUNT(*) FROM t1 WHERE ID1_with_null IS NULL AND ID2_with_null IS NULL;
+SELECT COUNT(*) FROM t1 WHERE ID_better=1;
+
+EXPLAIN SELECT * FROM t1
+  WHERE ID_better=1 AND ID1_with_null IS NULL AND ID2_with_null=3 ;
+EXPLAIN SELECT * FROM t1
+  WHERE ID_better=1 AND ID1_with_null=3 AND ID2_with_null=3 IS NULL ;
+EXPLAIN SELECT * FROM t1
+  WHERE ID_better=1 AND ID1_with_null IS NULL AND ID2_with_null IS NULL;
+
+DROP INDEX idx1 ON t1;
+CREATE UNIQUE INDEX idx1 ON t1(ID1_with_null,ID2_with_null);
+
+EXPLAIN SELECT * FROM t1
+  WHERE ID_better=1 AND ID1_with_null IS NULL AND ID2_with_null=3 ;
+EXPLAIN SELECT * FROM t1
+  WHERE ID_better=1 AND ID1_with_null=3 AND ID2_with_null IS NULL ;
+EXPLAIN SELECT * FROM t1
+  WHERE ID_better=1 AND ID1_with_null IS NULL AND ID2_with_null IS NULL;
+
+DROP TABLE t1;
Thread
bk commit into 5.0 tree (igor:1.2392) BUG#25407igor31 Jan