Bug #42846 | wrong result returned for range scan when using covering index | ||
---|---|---|---|
Submitted: | 13 Feb 2009 18:45 | Modified: | 18 Dec 2009 13:21 |
Reporter: | Shane Bester (Platinum Quality Contributor) | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: Optimizer | Severity: | S3 (Non-critical) |
Version: | 4.1.24, 5.0.74, 5.1.31, 6.0.9 | OS: | Any |
Assigned to: | Martin Hansson | CPU Architecture: | Any |
[13 Feb 2009 18:45]
Shane Bester
[13 Feb 2009 19:00]
MySQL Verification Team
another case that returns too many rows for the first select: drop table if exists `t1`; create table `t1`(`c1` varchar(20),`c2` char(20),key(`c2`,`c1`))engine=innodb ; insert into `t1`(`c1`,`c2`) values ('a', '0'),('b', '1'),('c', '2'),('d','4'),('g','9'),('y','43'),('ddd','1'); select * from `t1` where (c1 <> '0' and c2 <> 'c') or (c1 = '3' and c2 <= '5') or (c2 <> 'e' and c2 > '3'); select * from `t1`;
[13 Feb 2009 19:04]
Valeriy Kravchuk
Verified just as described: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 Server version: 5.1.31-enterprise-gpl-pro-debug MySQL Enterprise Server - Pro Ed ition Debug (GPL) Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> use test Database changed mysql> drop table if exists `t2`; Query OK, 0 rows affected (0.16 sec) mysql> create table `t2`(`c1` varchar(20),`c2` int,key (`c2`,`c1`)) engine=innod b; Query OK, 0 rows affected (0.14 sec) mysql> insert into `t2` values ('ddd','1'), ('c','2'), ('d','4'), ('g','9'); Query OK, 4 rows affected (0.00 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> select sql_no_cache * from `t2` where (c1 <> 'b' and c2 > '4') or (c2 <= '5' and c1 <> 2) -> or (c1 = 5 and c2 <> '2'); +------+------+ | c1 | c2 | +------+------+ | ddd | 1 | | c | 2 | | d | 4 | | g | 9 | | g | 9 | +------+------+ 5 rows in set (0.03 sec) mysql> select sql_no_cache * from `t2`; +------+------+ | c1 | c2 | +------+------+ | ddd | 1 | | c | 2 | | d | 4 | | g | 9 | +------+------+ 4 rows in set (0.00 sec) mysql> explain select sql_no_cache * from `t2` where (c1 <> 'b' and c2 > '4') or (c2 <= '5' and c1 <> 2) or (c1 = 5 and c2 <> '2')\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t2 type: range possible_keys: c2 key: c2 key_len: 5 ref: NULL rows: 3 Extra: Using where; Using index 1 row in set (0.03 sec) Looks like range scan for the covering index is broken.
[13 Feb 2009 19:15]
MySQL Verification Team
testcase for myisam: drop table if exists `t1`; create table `t1`(`c1` char(9),`c2` char(9),key(`c2`,`c1`))engine=myisam; insert into `t1`(`c1`,`c2`) values ('a', '0'),('b', '1'), ('c', '2'),('g','9'),('ddd','1'); select * from `t1` where (c2 >= '3' AND c1 = 'b') OR (c1 <> 'b' AND c2 > 'a') OR (c1 >= 'a' AND c2 >= '5') OR (c2 > '2' AND c2 <> '2'); workaround is to use "ignore index" hint.
[18 Feb 2009 9:08]
MySQL Verification Team
testcase for maria (6.0.9) drop table if exists `t1`; create table `t1` ( `a` char(3),`b` int,key `i`(`a`))engine=maria default charset=latin1; insert into `t1` values ('o',2),('o',2); select * from `t1` where (`b` <> 1 and `a` < 'a'); select * from `t1` ignore index(`i`) where (`b` <> 1 and `a` < 'a');
[13 May 2009 15:14]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/73950 2895 Martin Hansson 2009-05-13 Bug#42846: wrong result returned for range scan when using covering index When an open-ended range was merged with a closed range, the closed range copied the (non-existent) endpoint from the open range, thereby violating the range optimizer invariant that ranges must be disjoint. This led to duplicate answers. Fixed by not copying endpoints off open-ended ranges. @ mysql-test/r/range.result Bug#42846: Result @ mysql-test/t/range.test Bug#42846: Test case @ sql/opt_range.cc Bug#42846: Fix
[27 May 2009 6:40]
Martin Hansson
This is actually two bugs in the range optimizer module (SEL_ARG data structure). Two important points regarding the SEL_ARG structure: 1) It corresponds to a boolean expression (AND, OR) over ranges (e.g. 1 < field <= 10) 2) Whenever an OR expression appears, the sets matched by its two branches must not overlap, or a tuple in the overlapping area will appear twice in the result. 3) It is written in "keypart order", meaning that in each disjunct (OR-branch), keyparts appear in the same order as they do in the index. A legal SEL_ARG expression: 1 < keypart1 < 5 AND ( 2 < keypart2 < 4 OR keypart 2 < 5 ) OR keypart1 > 6 ( I use i < x < j as a shorthand for i < x AND x < j) The function key_or() creates a new OR node, adding its two arguments as branches, and maintains the delicate SEL_ARG invariant. This involves a lot of details that are irrelevant to this bug, such as tree balancing and memory management, so I set them aside. Problem #1 ---------- When OR'ing together expressions such as (1) 3 <= kp1 AND kp1 < 5 OR (2) 5 < kp1 AND kp2 = 3 OR - OR - (3) 3 <= kp1; The algorithm will detect that the expression (3) has the same lower endpoint as expression (1) and attempts to unify them, but the result is incorrectly 3 <= kp1 OR 5 < kp1 AND kp2 = 3. It misses that (3) has no higher endpoint. Problem #2 ---------- When OR'ing together expressions such as (1) 2 < kp1 < 10 AND kp2 = 2 OR (2) 10 <= kp1 < 20 AND kp2 = 3 - OR - (3) 1 < kp1 AND kp2 = 2 With problem 1 fixed, the algorithm will detect that the ranges (3) and (1) overlap and that (3) is open ended. Hence it copies only the lower endpoint: 1 < kp1. Since (3) is open ended, we need to look at (2)'s lower endpoint, 10 <= kp1, and copy that into (1). This creates the (still invalid) SEL_ARG expression (1b) 1 < kp1 < 10 AND kp2 = 2 OR (2) 10 <= kp1 < 20 AND kp2 = 3 What should be done? In this case, (3) should have been be split into two ranges: (3a) 1 < kp1 < 10 AND kp2 = 3 (same as 1b above) (3b) 20 <= kp1 AND kp2 = 3 And (2) has to be modified to (2') 10 <= kp1 < 20 AND ( kp2 = 3 OR kp2 = 2 ) Yielding the final result (3a) 1 < kp1 < 10 AND kp2 = 2 OR (2') 10 <= kp1 < 20 AND ( kp2 = 3 OR kp2 = 2 ) OR (3b) 20 <= kp1 AND kp2 = 3 The problem is symmetric, meaning the following. Above the ranges that trigger the bug have a lower endpoint and are open-ended. But the same happens for ranges open in the lower end. Also note that open-endedness is not required. We trigger the bug as soon as ranges overlap. I propose to fix Problem #1 first, as it is much simpler. When the patch is approved I'll file a second bug for Problem #2.
[2 Jun 2009 12:41]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/75460 2895 Martin Hansson 2009-06-02 Bug#42846: wrong result returned for range scan when using covering index When two range predicates were combined under an OR predicate, the algorithm tried to merge overlapping ranges into one. But the case when a range overlapped several other ranges was not handled. This lead to 1) ranges overlapping, which gave repeated results and 2) a range that overlapped several other ranges was cut off. Fixed by 1) Making sure that a ranges got an upper bound equal to the next range with a greater minimum. 2) Removing a coutinue statement @ mysql-test/r/group_min_max.result Bug#42846: Changed query plans @ mysql-test/r/range.result Bug#42846: Test result. @ mysql-test/t/range.test Bug#42846: Test case. @ sql/opt_range.cc Bug#42846: The fix. Part1: Previously, both endpoints from key2 were copied, which is not safe. Since ranges are processed in ascending order of minimum endpoints, it is safe to copy the minimum endpoint from key2 but not the maximum. The maximum may only be copied if there is no other range or the other range's minimum is greater than key2's maximum. Part 2: Do not simply move to the next key part, the range in key2 may have to be split up, creating more ranges.
[2 Jun 2009 13:59]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/75468 2895 Martin Hansson 2009-06-02 Bug#42846: wrong result returned for range scan when using covering index When two range predicates were combined under an OR predicate, the algorithm tried to merge overlapping ranges into one. But the case when a range overlapped several other ranges was not handled. This lead to 1) ranges overlapping, which gave repeated results and 2) a range that overlapped several other ranges was cut off. Fixed by 1) Making sure that a ranges got an upper bound equal to the next range with a greater minimum. 2) Removing a continue statement @ mysql-test/r/group_min_max.result Bug#42846: Changed query plans @ mysql-test/r/range.result Bug#42846: Test result. @ mysql-test/t/range.test Bug#42846: Test case. @ sql/opt_range.cc Bug#42846: The fix. Part1: Previously, both endpoints from key2 were copied, which is not safe. Since ranges are processed in ascending order of minimum endpoints, it is safe to copy the minimum endpoint from key2 but not the maximum. The maximum may only be copied if there is no other range or the other range's minimum is greater than key2's maximum.
[5 Oct 2009 8:06]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/85704 3153 Martin Hansson 2009-10-05 Bug#42846: wrong result returned for range scan when using covering index When two range predicates were combined under an OR predicate, the algorithm tried to merge overlapping ranges into one. But the case when a range overlapped several other ranges was not handled. This lead to 1) ranges overlapping, which gave repeated results and 2) a range that overlapped several other ranges was cut off. Fixed by 1) Making sure that a range got an upper bound equal to the next range with a greater minimum. 2) Removing a continue statement @ mysql-test/r/group_min_max.result Bug#42846: Changed query plans @ mysql-test/r/range.result Bug#42846: Test result. @ mysql-test/t/range.test Bug#42846: Test case. @ sql/opt_range.cc Bug#42846: The fix. Part1: Previously, both endpoints from key2 were copied, which is not safe. Since ranges are processed in ascending order of minimum endpoints, it is safe to copy the minimum endpoint from key2 but not the maximum. The maximum may only be copied if there is no other range or the other range's minimum is greater than key2's maximum.
[5 Oct 2009 8:10]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/85705 3153 Martin Hansson 2009-10-05 Bug#42846: wrong result returned for range scan when using covering index When two range predicates were combined under an OR predicate, the algorithm tried to merge overlapping ranges into one. But the case when a range overlapped several other ranges was not handled. This lead to 1) ranges overlapping, which gave repeated results and 2) a range that overlapped several other ranges was cut off. Fixed by 1) Making sure that a range got an upper bound equal to the next range with a greater minimum. 2) Removing a continue statement @ mysql-test/r/group_min_max.result Bug#42846: Changed query plans @ mysql-test/r/range.result Bug#42846: Test result. @ mysql-test/t/range.test Bug#42846: Test case. @ sql/opt_range.cc Bug#42846: The fix. Part1: Previously, both endpoints from key2 were copied, which is not safe. Since ranges are processed in ascending order of minimum endpoints, it is safe to copy the minimum endpoint from key2 but not the maximum. The maximum may only be copied if there is no other range or the other range's minimum is greater than key2's maximum.
[5 Oct 2009 8:40]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/85709 3154 Martin Hansson 2009-10-05 [merge] Merge of Bug#42846
[9 Oct 2009 9:30]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/86310 3156 Martin Hansson 2009-10-09 Bug#42846: wrong result returned for range scan when using covering index When two range predicates were combined under an OR predicate, the algorithm tried to merge overlapping ranges into one. But the case when a range overlapped several other ranges was not handled. This lead to 1) ranges overlapping, which gave repeated results and 2) a range that overlapped several other ranges was cut off. Fixed by 1) Making sure that a range got an upper bound equal to the next range with a greater minimum. 2) Removing a continue statement @ mysql-test/r/group_min_max.result Bug#42846: Changed query plans @ mysql-test/r/range.result Bug#42846: Test result. @ mysql-test/t/range.test Bug#42846: Test case. @ sql/opt_range.cc Bug#42846: The fix. Part1: Previously, both endpoints from key2 were copied, which is not safe. Since ranges are processed in ascending order of minimum endpoints, it is safe to copy the minimum endpoint from key2 but not the maximum. The maximum may only be copied if there is no other range or the other range's minimum is greater than key2's maximum.
[9 Oct 2009 11:51]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/86337 3642 Martin Hansson 2009-10-09 [merge] Merge of Bug#42846 to -pe
[9 Oct 2009 15:35]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/86412 3157 Martin Hansson 2009-10-09 [merge] Merge of bug#42846
[14 Oct 2009 14:39]
Bugs System
Pushed into 5.1.41 (revid:joro@sun.com-20091014143611-cphb0enjlx6lpat1) (version source revid:satya.bn@sun.com-20091013071829-zc4c3go44j6re592) (merge vers: 5.1.40) (pib:13)
[15 Oct 2009 23:53]
Paul DuBois
Noted in 5.1.41 changelog. Incorrect handling of range predicates combined with OR operators could yield incorrect results. Setting report to NDI pending 5.5.x+.
[22 Oct 2009 6:33]
Bugs System
Pushed into 6.0.14-alpha (revid:alik@sun.com-20091022063126-l0qzirh9xyhp0bpc) (version source revid:alik@sun.com-20091019135554-s1pvptt6i750lfhv) (merge vers: 6.0.14-alpha) (pib:13)
[22 Oct 2009 7:05]
Bugs System
Pushed into 5.5.0-beta (revid:alik@sun.com-20091022060553-znkmxm0g0gm6ckvw) (version source revid:alik@sun.com-20091019131708-bc6pv55x6287a0wc) (merge vers: 5.5.0-beta) (pib:13)
[22 Oct 2009 19:57]
Paul DuBois
Noted in 5.5.0, 6.0.14 changelogs.
[18 Dec 2009 10:41]
Bugs System
Pushed into 5.1.41-ndb-7.1.0 (revid:jonas@mysql.com-20091218102229-64tk47xonu3dv6r6) (version source revid:jonas@mysql.com-20091218095730-26gwjidfsdw45dto) (merge vers: 5.1.41-ndb-7.1.0) (pib:15)
[18 Dec 2009 10:56]
Bugs System
Pushed into 5.1.41-ndb-6.2.19 (revid:jonas@mysql.com-20091218100224-vtzr0fahhsuhjsmt) (version source revid:jonas@mysql.com-20091217101452-qwzyaig50w74xmye) (merge vers: 5.1.41-ndb-6.2.19) (pib:15)
[18 Dec 2009 11:11]
Bugs System
Pushed into 5.1.41-ndb-6.3.31 (revid:jonas@mysql.com-20091218100616-75d9tek96o6ob6k0) (version source revid:jonas@mysql.com-20091217154335-290no45qdins5bwo) (merge vers: 5.1.41-ndb-6.3.31) (pib:15)
[18 Dec 2009 11:25]
Bugs System
Pushed into 5.1.41-ndb-7.0.11 (revid:jonas@mysql.com-20091218101303-ga32mrnr15jsa606) (version source revid:jonas@mysql.com-20091218064304-ezreonykd9f4kelk) (merge vers: 5.1.41-ndb-7.0.11) (pib:15)
[18 Dec 2009 13:21]
MC Brown
Already noted in earlier changelogs.