Reputation: 45
I'm trying to optimize the following simple Entity Framework query to retreieve all the products from the same group
var query = from p in ctx.Products
where p.GroupId == ( from q in ctx.Products
where q.Id == new Guid(".....")
select q.GroupId).FirstOrDefault()
select p;
After checking the generated sql using SQL Server Profiler I see this query
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[GroupId] AS [GroupId],
[Extent1].[Name] AS [Name],
[Extent1].[Code] AS [Code]
FROM [inv].[Products] AS [Extent1]
LEFT OUTER JOIN (SELECT TOP (1) [Extent2].[GroupId] AS [GroupId]
FROM [inv].[Products] AS [Extent2]
WHERE cast('.....' as uniqueidentifier) = [Extent2].[Id] ) AS [Limit1] ON 1 = 1
LEFT OUTER JOIN (SELECT TOP (1) [Extent3].[GroupId] AS [GroupId]
FROM [inv].[Products] AS [Extent3]
WHERE cast('.....' as uniqueidentifier) = [Extent3].[Id] ) AS [Limit2] ON 1 = 1
LEFT OUTER JOIN (SELECT TOP (1) [Extent4].[GroupId] AS [GroupId]
FROM [inv].[Products] AS [Extent4]
WHERE cast('.....' as uniqueidentifier) = [Extent4].[Id] ) AS [Limit3] ON 1 = 1
LEFT OUTER JOIN (SELECT TOP (1) [Extent5].[GroupId] AS [GroupId]
FROM [inv].[Products] AS [Extent5]
WHERE cast('.....' as uniqueidentifier) = [Extent5].[Id] ) AS [Limit4] ON 1 = 1
LEFT OUTER JOIN (SELECT TOP (1) [Extent6].[Id] AS [Id]
FROM [inv].[Products] AS [Extent6]
WHERE cast('.....' as uniqueidentifier) = [Extent6].[Id] ) AS [Limit5] ON 1 = 1
LEFT OUTER JOIN (SELECT TOP (1) [Extent7].[Id] AS [Id]
FROM [inv].[Products] AS [Extent7]
WHERE cast('.....' as uniqueidentifier) = [Extent7].[Id] ) AS [Limit6] ON 1 = 1
WHERE ([Extent1].[GroupId] = (CASE WHEN ([Limit1].[GroupId] IS NULL)
THEN cast('00000000-0000-0000-0000-000000000000' as uniqueidentifier)
ELSE [Limit2].[GroupId] END))
AND (CASE WHEN ([Limit3].[GroupId] IS NULL)
THEN cast('00000000-0000-0000-0000-000000000000' as uniqueidentifier)
ELSE [Limit4].[GroupId] END IS NOT NULL)
Why is it generating so many identical JOINs? Is there any option to remove the final null casting? Could you please suggest ways to improve the generated sql?
I've tested also with LINQPad and that one is generating normal SQL
-- Region Parameters
DECLARE @p0 UniqueIdentifier = '....'
-- EndRegion
SELECT [t0].[Id], [t0].[GroupId], [t0].[Name], [t0].[Description], [t0].[Code]
FROM [inv].[Products] AS [t0]
WHERE [t0].[GroupId] = ((
SELECT TOP (1) [t1].[GroupId]
FROM [inv].[Products] AS [t1]
WHERE [t1].[Id] = @p0
))
Upvotes: 1
Views: 565
Reputation: 10398
If you're really dealing with a primary key (id) here, I'm not sure that you need the FirstOrDefault. Would the following accomplish the same goal:
var query = from groupProduct in ctx.Products
where groupProduct.Id == someGuid // This should return only one result
join childProduct in ctx.Products
on groupProduct.Id equals childProduct.GroupId
select childProduct
And the generated SQL is
SELECT
[Extent2].[Id] AS [Id],
[Extent2].[GroupId] AS [GroupId],
[Extent2].[Name] AS [Name],
[Extent2].[Code] AS [Code]
FROM [inv].[Products] AS [Extent1]
INNER JOIN [inv].[Products] AS [Extent2] ON [Extent1].[Id] = [Extent2].[GroupId]
WHERE cast('....' as uniqueidentifier) = [Extent1].[Id]
Upvotes: 1
Reputation: 4146
Try the following, its two statements but should produce smoother SQL if that is what you are after:
var groupId = ctx.Products.Where(p=> p.Id = new Guid(...).Select(p=> p.GroupId).FirstOrDefault();
if(groupId.HasValue)
{
var query = ctx.Products.Where(p=> p.GroupId == groupId).Select(p=> p);
}
This assumes that Id is an int, if it is not, use the appropriate boundary check.
Upvotes: 0