Quantcast
Channel: Entity Framework
Viewing all articles
Browse latest Browse all 10318

Edited Issue: Multiple correlated subqueries with paging should generate CROSS JOIN instead of CROSS APPLY [618]

$
0
0
This is a common scenario for customers who do multiple Include() calls within their Linq queries and where more than one of those Include() calls are to one-to-many collections. A customer explained the issue in great detail at http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/5b9db2f3-f156-4ff7-b764-f67669a2a26d. This is a rather complex scenario, but apparently not so uncommon.

For example, suppose Projects has a 1..* relationship to ForeignLoggers AND ALSO a 1..* relationship to Loggers. Furthermore, suppose that Loggers has a 1..* relationship to Inverters AND ALSO a 1..* relationship to Sensors. Now have the following query:
var query = from p in ctx.Projects.Include("Loggers")
.Include("ForeignLoggers")
.Include("Loggers.Sensors")
.Include("Loggers.Inverters")
.Include("Loggers.Inverters.InverterType")

This query will produce a query that includes a CROSS APPLY over the UNION ALL of the Sensors and the Inverters that are related to the Loggers.

This query is very complex by nature but the query compiler could be enhanced to detect cases like this where the CROSS APPLY can be transformed to a CROSS JOIN. If in this example query we leave out the inclusion of ForeignLoggers then the code generated includes an OUTER APPLY instead of a CROSS APPLY.

Queries in the shape of:
A CROSS APPLY (
SELECT [...] FROM B
WHERE A.I = B.J AND [...]
UNION ALL
SELECT [...] FROM C
WHERE A.K = C.L AND [...]
) AS [UnionAll1]

Could be transformed into:
A CROSS JOIN (
SELECT [...] FROM B
WHERE [...]
UNION ALL
SELECT [...] FROM C
WHERE [...]
) AS [UnionAll1] ON [UnionAll1].J = A.I AND [UnionAll1].L = A.K

if all the following are true:
1) there is a one-to-many relationship path from A to B and from A to C
2) Neither B nor C are TVFs, nor do they contain a reference to a TVF
3) The union exposes the columns from B and C that are involved in the relationships from A

The transformation should occur inside System.Data.Entity.Core.Query.PlanCompiler.ApplyOpRules and optionally in System.Data.Entity.Core.Query.PlanCompiler.FilterOpRules if it is part of the cases where OuterApply is transformed into CrossApply.

Note that the OuterApplyOp is being created by the subquery tracking visitor, thus appearing like there could be room for improvement from within the subquery tracking visitor instead of having to transform the OuterApply to a LeftOuterJoin, but this would require additional investigation.

Find a repro scenario in the attached zip file.

Viewing all articles
Browse latest Browse all 10318

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>