[MDEV-5161] Wrong result (missing rows) with semijoin, LEFT JOIN, ORDER BY, constant table Created: 2013-10-20 Updated: 2014-01-29 Resolved: 2013-11-21 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | None |
| Affects Version/s: | 10.0.4, 5.3.12, 5.5.33a |
| Fix Version/s: | 5.5.35, 10.0.7 |
| Type: | Bug | Priority: | Major |
| Reporter: | Elena Stepanova | Assignee: | Sergei Petrunia |
| Resolution: | Fixed | Votes: | 0 |
| Labels: | None | ||
| Issue Links: |
|
||||||||||||||||
| Description |
|
The test case is nearly identical to the one provided in the comment to Test case:
Actual result:
Expected result:
|
| Comments |
| Comment by Sergei Petrunia [ 2013-11-13 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
FROM t1, t2 WHERE pk IN ( SELECT pk FROM t1 LEFT JOIN t3 ON (c1 = c3 ) ) EXPLAIN EXTENDED shows: ... from `j2`.`t1` semi join (`j2`.`t3`) join `j2`.`t1` where (`j2`.`t1`.`pk` = `j2`.`t1`.`pk`) note that
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-11-13 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Another interesting observation is that table elimination could theoretically remove the LEFT JOIN from the subquery, but that didn't happen. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-11-13 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
If I disallow pullout of parts of outer joins out of semi-joins, I get EXPLAIN like this: +EXPLAIN EXTENDED The warning text shows that the LEFT JOIN is here. However, the query result is still incorrect. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-11-13 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Tracing this EXPLAIN MariaDB [j2]> explain SELECT * FROM t1a, t2 WHERE pk IN ( SELECT pk FROM t1 LEFT JOIN t3 ON (c1 = c3 ) ) ORDER BY c2, c1;
-----
----- it seems that SJ_TMP_TABLE::sj_weedout_check_row() is invoked correclty for | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-11-13 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The issue doesn't depend on join buffering. I can get a wrong result when it is not used, too: MariaDB [j4]> explain SELECT * FROM t1, t2 WHERE pk IN ( SELECT pk FROM t1 LEFT JOIN t3 ON (c1 = c3 ) ) ORDER BY c2, c1;
-----
----- MariaDB [j4]> SELECT * FROM t1, t2 WHERE pk IN ( SELECT pk FROM t1 LEFT JOIN t3 ON (c1 = c3 ) ) ORDER BY c2, c1;
---
--- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-11-14 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Without join buffering, the problem is still the same: SJ_TMP_TABLE::sj_weedout_check_row() checks rowid of table t1a (the outer t1), however, that table always has: (gdb) p h->ref_length and that's why the query produces only one row instead of five. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-11-14 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Ok, I think I get it. The problem seems to be caused by doing filesort on the first table. After that, join execution reads table rows with rr_unpack_from_buffer(). However, that function doesn't update the rowid at join->join_tab[1].table->ref. Duplicate Weedout code sees the same rowid all the time, and concludes that all row combinations except for the first one are duplicates. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-11-14 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Two thoughts: 1. If the first table is doing a post-create_sort_index() read, we need to 2. Duplicate Elimination and create_sort_index. 2.1 Suppose there is no join buffering. 2.2 Suppose, join buffering is used somewhere within the duplicate elimination | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-11-14 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Exploring thought#2. When I try to debug the testcase that is not using the join buffering, I see
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-11-14 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The case where no join buffering is used could be solved with this approach: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-11-14 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
What is not clear is what should we do when join buffering is used. Look at the EXPLAIN in the comment for this bug here: It has both join buffering and "Using filesort" (which means: run filesort() for the first table, then do join with other tables). "Using join buffer" will break the ordering that was produced by filesort. Apparently, the bug is not [only] in Duplicate Elimination. join buffer and order by optimizations also work incorrectly. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-11-15 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Created a testcase for the problem mentioned in the previous comment. Filed it as | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-11-18 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Now I have a patch for | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-11-18 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Interesting.. there is code in setup_semijoin_dups_elimination() which disables "Using filesort": Fixed LP bug #901478. It seems, a problem similar to this one was encountered before? | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-11-18 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
The fix looks like this: Make sure that possible sorting of rows from the head table and it doesn't work for our testcase, because join->get_sort_by_join_tab()=NULL, which is caused by JOIN::sort_by_table being NULL. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sergei Petrunia [ 2013-11-19 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
I've made a fix that runs get_sort_by_table() after const. tables have been detected and read. This caused get_sort_by_join_tab() to return the first JOIN_TAB in this example. Tests pass, including valgrind. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Daniel Bartholomew [ 2014-01-29 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
http://bazaar.launchpad.net/~maria-captains/maria/5.5/revision/3963.1.2 |