[MDEV-4817] Optimizer fails to optimize expression of the form 'FOO' IS NULL Created: 2013-07-26 Updated: 2018-07-25 Resolved: 2013-09-03 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | None |
| Affects Version/s: | 5.5.32 |
| Fix Version/s: | 5.5.33 |
| Type: | Bug | Priority: | Major |
| Reporter: | Archie Cobbs (Inactive) | Assignee: | Sergei Petrunia |
| Resolution: | Fixed | Votes: | 0 |
| Labels: | None | ||
| Environment: |
openSUSE 12.1 |
||
| Issue Links: |
|
||||||||||||||||
| Description |
|
This is a copy of this MySQL bug: http://bugs.mysql.com/bug.php?id=69359 I am filing it here in hopes it will get more attention than from the MySQL folks. Note, this bug occurs in BOTH MySQL and MariaDB. Restatement of bug follows... See http://stackoverflow.com/questions/16848190/mysql-why-isnt-foo-is-null-optimized-away for a description. Quoting that here: I have two tables Person and Message and the latter has a foreign key to the former. Each table has id as the primary key column, and the Person table also has a column personId which is (uniquely) indexed. The query below should take advantage of the personId key index, but instead MySQL requires scanning the entire Message table for some reason:
But when I comment out the 'M002649397' IS NULL OR clause (which has no effect on the result), the query suddenly gets more efficient:
The bug is that the 'M002649397' IS NULL expression, which is always false, is not being optimized away. Here is a schema to test with:
|
| Comments |
| Comment by Sergei Petrunia [ 2013-07-26 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The query has form m LEFT JOIN p ON ... LEFT JOIN allows only one join order: m, p. (This is because LEFT JOIN needs to find all records in `m`, regardless If we take a careful look at the WHERE clause, we can see that is only `p`.`personId` = 'M002649397' This means that we're not interested in results of LEFT JOIN that have a Once we have INNER JOIN, we can use both join orders:
When we use the join order "p, m" (like the second EXPLAIN does), we can The problem here seems to be that the optimizer is unable to convert left When the WHERE clause is just `p`.`personId` = 'M002649397' then conversion works (check out EXPLAIN EXTENDED - it shows "JOIN") When the WHERE clause is 'M002649397' IS NULL OR `p`.`personId` = 'M002649397'; then conversion doesn't work. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-07-26 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
I was able to replicate: MariaDB [j9]> EXPLAIN SELECT `m`.*
-----
----- MariaDB [j9]>
-----
----- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-07-26 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
How to fill the test dataset: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-07-26 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
One may ask, doesn't MySQL (or MariaDB) optimizer has module that removes parts of WHERE condition that are known to be false. Yes, it does. The problem is that outer-to-inner join conversion step is run before the constant-condition-removal module is run (there are reasons for this). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-07-26 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Indeed Breakpoint 1, simplify_joins (join=0x7fff9803cfe8, join_list=0x7fff98007ca0, conds=0x7fff98008238, top=true, in_sj=false) at /home/psergey/dev2/5.5/sql/sql_select.cc:12788 (gdb) p dbug_print_item(conds) (gdb) set $second= ((Item_cond_or*)conds) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-07-26 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
(gdb) set $first= ((Item_cond_or*)conds) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-07-26 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Maybe, we could remove items that have item->const_item() && !item->is_expensive() && item->val_int() == 0 from having item->not_null_tables() put into not_null_tables_cache. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-07-31 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Committed a patch. It needs to be tested and reviewed. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-09-03 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The fix was pushed into 5.5, and will be available in MariaDB 5.5.33. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-09-03 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Archie, thanks for reporting this bug here. The fix should be an improvement for the MariaDB optimizer. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Archie Cobbs (Inactive) [ 2013-09-03 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Thanks for the quick turnaround! |