[MDEV-7097] Sub-Queries and Outer Joins may return NULL instead of (existing) value over ODBC Created: 2014-11-12 Updated: 2014-11-24 Resolved: 2014-11-16 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Storage Engine - Connect |
| Affects Version/s: | 10.0.12, 10.0.14, 10.1.1 |
| Fix Version/s: | 10.0.15 |
| Type: | Bug | Priority: | Major |
| Reporter: | Björn Schneider | Assignee: | Olivier Bertrand |
| Resolution: | Fixed | Votes: | 0 |
| Labels: | connect-engine | ||
| Environment: |
Windows 2008 R2 Server (amd64), MariaDB 10.0.12 (Windows, amd64), Oracle ODBC 11.02.00.03 (with Oracle 09.02.0060 on another server) as well as MySQL ODBC 5.03.04.00 ANSI driver (with MySQL Server 5.5.40-0ubuntu on another server) |
||
| Description |
|
On certain conditions, a sub-select or outer join may return NULL instead of the actually existing value. You can test that simply with a MySQL table, e.g. `demo.subselectdemo`:
Ideally on another computer, create a DSN with the MySQL ODBC driver (the MariaDB ODBC driver didn't work for me at all) to that database instance. Then create a database on that computer with a CONNECT-Table, e.g.:
Now try the following query:
It returns:
It should return something like the following, which you can verify on the origin DB with the "real" table:
This might have to do with CONNECT's limitation to "forward cursors". But similar happens to me with at least Oracle ODBC with a "LEFT OUTER JOIN" on two different, large (>5000 entries) tables, where the "key" used to correlate the entries is pretty random. After a few thousand entries, the OUTER JOIN is always NULL, although there is a corresponding entry in the other table - often it was actually found already for an earlier entry, e.g.:
A second OUTER JOIN in the same query stops even earlier, e.g.:
I hope you can solve both issues by fixing the "sub-select" issue; if this ticket needs to be splitted, I can try to create a proper test case for the JOIN-issue. |
| Comments |
| Comment by Elena Stepanova [ 2014-11-12 ] | |||||||||||||||||||||||||||||||
|
Thanks for the report. I could reproduce it with e.g. postgresql for a remote table:
| |||||||||||||||||||||||||||||||
| Comment by Olivier Bertrand [ 2014-11-15 ] | |||||||||||||||||||||||||||||||
|
This is a general problem concerning correlated subqueries. What CONNECT does, when a table is accessed several times is to execute a "rewind" allowing to restart reading it from the beginning. Now, to deal with ODBC tables there are several solutions:
All solutions raise some problems:
It would be nice to restrict these only when needed. However, I am not sure whether the storage engine can determine if the table is used in a correlated subquery. | |||||||||||||||||||||||||||||||
| Comment by Olivier Bertrand [ 2014-11-16 ] | |||||||||||||||||||||||||||||||
|
This fix implements solution (2) by default. The reason why is that it does not impact using the table out of correlated subquery. However, correlated subqueries last very long on medium and big table, particularly when remote. For instance, on a table having 4545 rows the query:
takes 11 minutes on my machine. Slightly better is to use solution (3).
Doing so the same query last 6 minutes 25 seconds. However the table will no more use extended fetch, which can impact all other usages. A solution is to define a table to use only in correlated subqueries:
Of course, on big tables, those queries would last forever. However I did not implement solution (4) because it is very simple to make a local copy of the table to use in correlated subqueries, for instance:
(It could use any other engine) Now the query:
takes... 0.30 seconds! I don' know whether this will also fix the outer join problem. As a matter of facts, I could not reproduce this bug, even before I implemented the fix. | |||||||||||||||||||||||||||||||
| Comment by Olivier Bertrand [ 2014-11-21 ] | |||||||||||||||||||||||||||||||
|
Finally I added the implementation of solution (4) The main reason for doing so is that it is not penalising when the table is not used in a correlated sub-query. Indeed, the memory result set is not constructed on the first read (as the result set size is not known) It is allocated and populated during the second read that is still done normally. The third and subsequent read directly get the result from the stored set. As you will see it is about 6 times faster than the default method. Using a release server (previously it was a debug one) the execution times and option setting are:
Note: It is still not the default to avoid memory problems with big tables. Solution (3) should be reguarded as an alternative when getting memory problems. It might slow down the execution of all queries even not in correlated sub-queries (if using a scrollable cursor is slower than using a forward only cursor), and may not be supported by all drivers. About the incredible execution time obtained using a local copy of the remote table, it is probably due to a MariaDB optimisation that transform the query to something else, probably a join. This should prompt you to avoid using correlated subqueries by all means and look for possible alternative. |