I have a problem with a relatively simple query and the execution plan Access choose for it.
The query is of this form
SELECT somethings
FROM A INNER JOIN (B INNER JOIN (C INNER JOIN D ON ...) ON ...) ON ...
WHERE A.primaryKey= 1 AND D.d = 2;
C and D have relatively few rows. A and B have a few thousands rows.
The query, which returns 2 rows (not sure if this is pertinent) is really slow. It runs in 17 seconds. If I remove the AND D.d = 2
part of the where clause, the query now returns 4 rows and run instantly.
So my understanding is that the JET engine could run the query without the filter on D.d instantly, then execute the said filter instantly (only 4 rows to filter). Therefor it should not be too much longer to run the query with the D.d = 2
filter.
I tried to create a sub query without the filter and include this in another query that would just filter the result, but it's still slow. My guess is that the JET engine is smart enough to "flatten" the sub-queries so the result is the same.
Since I was unable to make the query run as I wished I used the JETSHOWPLAN thingy so that Access would output it's execution plan. Here is what I found:
For the fast query (the one without D.d = 2
) the first step of the query plan is to apply the A.primaryKey = 1
filter on the A table. This result in a data set of 1 row out of more than 30000. Then the joins seems to be executed from A to D using index with a data set that never goes over 4 rows.
The slow query seems to be executed in the revers order. D and C are joined first then D.d = 2
is tested. After that, the joins from C to A are executed. By doing this this way the data that needs to be joined from D to C, from C to B and from B to A is much larger. When all the JOIN are executed and before A.primaryKey=1
is executed the data set will have 120K rows.
Is there a way I could force the right query plan on Access?
I hope I was clear. Let me know if I should post the query plans. I did not because they are quite large.
Thanks in advance,
mp
I finally got it to work by mixing things up until the query planner agreed with me. I isolated the "A.primaryKey= 1" in a sub-query to ensure it's executed before A is joined to B. It's something like this :