[MDEV-5606] range optimizer: "x < y" is sargable, while "y > x" is not Created: 2014-02-03  Updated: 2014-02-12  Resolved: 2014-02-04

Status: Closed
Project: MariaDB Server
Component/s: None
Affects Version/s: 5.5.35, 10.0.7
Fix Version/s: 10.0.8

Type: Bug Priority: Major
Reporter: Sergei Petrunia Assignee: Sergei Petrunia
Resolution: Fixed Votes: 0
Labels: None


 Description   

Query plans produced by range optimizer depend on whether the condition has form "X < Y", or "Y >X".

Example:

create table ten(a int);
insert into ten values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table one_k(a int);
insert into one_k select A.a + B.a* 10 + C.a * 100 from ten A, ten B, ten C;
alter table one_k add key(a);

explain select * from ten, one_k where one_k.a < ten.a;
+------+-------------+-------+------+---------------+------+---------+------+------+------------------------------------------------+
| id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                                          |
+------+-------------+-------+------+---------------+------+---------+------+------+------------------------------------------------+
|    1 | SIMPLE      | ten   | ALL  | NULL          | NULL | NULL    | NULL |   10 |                                                |
|    1 | SIMPLE      | one_k | ALL  | a             | NULL | NULL    | NULL | 1148 | Range checked for each record (index map: 0x1) |
+------+-------------+-------+------+---------------+------+---------+------+------+------------------------------------------------+

now, the same query with changed WHERE:

mysql> explain select * from ten, one_k where ten.a > one_k.a;
+------+-------------+-------+-------+---------------+------+---------+------+------+--------------------------------------------------------------+
| id   | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra                                                        |
+------+-------------+-------+-------+---------------+------+---------+------+------+--------------------------------------------------------------+
|    1 | SIMPLE      | ten   | ALL   | NULL          | NULL | NULL    | NULL |   10 |                                                              |
|    1 | SIMPLE      | one_k | index | a             | a    | 5       | NULL | 1148 | Using where; Using index; Using join buffer (flat, BNL join) |
+------+-------------+-------+-------+---------------+------+---------+------+------+--------------------------------------------------------------+

The problem can be only observed if there is a table field on the other side of the comparison. Besides "range checked for each record", the optimizer may miss regular plans:

create table t2 (a int primary key, b int);
insert into t2 select a,a from ten;

mysql> explain select * from t2, one_k where one_k.a < t2.b  and t2.a=1;
+------+-------------+-------+-------+---------------+---------+---------+-------+------+--------------------------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra                    |
+------+-------------+-------+-------+---------------+---------+---------+-------+------+--------------------------+
|    1 | SIMPLE      | t2    | const | PRIMARY       | PRIMARY | 4       | const |    1 |                          |
|    1 | SIMPLE      | one_k | range | a             | a       | 5       | NULL  |    1 | Using where; Using index |
+------+-------------+-------+-------+---------------+---------+---------+-------+------+--------------------------+

mysql> explain select * from t2, one_k where t2.b > one_k.a   and t2.a=1;
+------+-------------+-------+-------+---------------+---------+---------+-------+------+--------------------------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra                    |
+------+-------------+-------+-------+---------------+---------+---------+-------+------+--------------------------+
|    1 | SIMPLE      | t2    | const | PRIMARY       | PRIMARY | 4       | const |    1 |                          |
|    1 | SIMPLE      | one_k | index | a             | a       | 5       | NULL  | 1148 | Using where; Using index |
+------+-------------+-------+-------+---------------+---------+---------+-------+------+--------------------------+



 Comments   
Comment by Sergei Petrunia [ 2014-02-03 ]

Repeatable on MariaDB 5.5, MariaDB 10.0.
Repeatable on MySQL 5.5, not repeatable on MySQL 5.6.

Comment by Sergei Petrunia [ 2014-02-03 ]

The reason it's not repeatable on MySQL 5.6 is this fix:

jorgen.loland@oracle.com-20120314131055-ml54x9deueqfsff4
BUG#13701206: WHERE A>=B DOES NOT GIVE SAME EXECUTION PLAN
AS WHERE B<=A (RANGE OPTIMIZER)

The bug doesn't have its own testcase (although it changes the results for some other test cases).

I don't think I 100% agree with the patch. I think a more straightforward fix is possible.

Comment by Sergei Petrunia [ 2014-02-03 ]

The patch in mysql-5.6: http://bazaar.launchpad.net/~mysql/mysql-server/5.6/revision/jorgen.loland@oracle.com-20120314131055-ml54x9deueqfsff4

Generated at Thu Feb 08 07:05:39 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.