簡體   English   中英

實體框架簡單的子查詢生成難看的SQL

[英]entity framework simple subquery generates ugly sql

我正在嘗試優化以下簡單的Entity Framework查詢,以檢索同一組中的所有產品

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;

使用SQL Server Profiler檢查生成的sql后,我看到此查詢

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)

為什么會生成這么多相同的JOIN? 是否可以刪除最終的空類型轉換? 您能否提出一些改進生成的sql的方法?

我也用LINQPad進行了測試,並且正在生成普通的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
    ))

如果您確實在這里處理主鍵(id),則不確定您是否需要FirstOrDefault。 以下內容是否可以實現相同的目標:

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

生成的SQL是

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]

嘗試以下兩個語句,但是如果您要這樣做,則應產生更平滑的SQL:

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);
}

假定Id是一個int,如果不是,則使用適當的邊界檢查。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM