c# - Entity Framework - Distinct 和 Max 生成巨大(且缓慢)的查询

标签 c# sql sql-server entity-framework entity-framework-6

我正在尝试从旧的经典 ASP 项目复制任何现有查询的结果。查询相当简单。

SELECT DISTINCT TOP 10 MAX(H.HistID) as MaxHID, C.CompanyID,C.CompanyName, P.ProsID, P.ProsName, P.Online 
FROM HISTORY H, PROSPECTUS P, COMPANY C 
WHERE H.ProsID = P.ProsID 
and P.CompanyID = C.CompanyID 
and H.UserID = 2712
GROUP BY C.CompanyID, C.CompanyName, P.ProsID, P.ProsName, P.Online 
ORDER BY MaxHID DESC

我已经(至少尝试过)使用 Entity Framework 和以下查询来复制它:

MyContext.HistoryItems.Where(h => h.UserId == userId)
    .GroupBy(h => new { h.Prospectus.Family.Id, h.ProsId })
    .Select(h => new { Max = h.Max(i => i.Id), Item = h.FirstOrDefault() })
    .OrderByDescending(h => h.Max)
    .Take(10)
    .Select(h => h.Item);

(GroupBy() 旨在复制原始查询中的 DISTINCT 行为。)

此查询产生完全相同的数据,但执行大约需要 10 秒。我查看了 EF 生成的查询,它是一个怪物。

SELECT TOP (10) 
    [Project6].[HistId] AS [HistId], 
    [Project6].[UserID] AS [UserID], 
    [Project6].[ProsID] AS [ProsID], 
    [Project6].[HDate] AS [HDate], 
    [Project6].[ProsDocId] AS [ProsDocId]
    FROM ( SELECT 
        [Project5].[HistId] AS [HistId], 
        [Project5].[UserID] AS [UserID], 
        [Project5].[ProsID] AS [ProsID], 
        [Project5].[HDate] AS [HDate], 
        [Project5].[ProsDocId] AS [ProsDocId], 
        [Project5].[C1] AS [C1]
        FROM ( SELECT 
            [Project4].[HistId] AS [HistId], 
            [Project4].[UserID] AS [UserID], 
            [Project4].[ProsID1] AS [ProsID], 
            [Project4].[HDate] AS [HDate], 
            [Project4].[ProsDocId] AS [ProsDocId], 
            (SELECT 
                MAX([Extent5].[HistId]) AS [A1]
                FROM  [dbo].[History] AS [Extent5]
                INNER JOIN [dbo].[Prospectus] AS [Extent6] ON [Extent5].[ProsID] = [Extent6].[ProsId]
                WHERE ([Extent5].[UserID] = @p__linq__0) AND (([Project4].[CompanyId] = [Extent6].[CompanyId]) OR (1 = 0)) AND ([Project4].[ProsID] = [Extent5].[ProsID])) AS [C1]
            FROM ( SELECT 
                [Project2].[ProsID] AS [ProsID], 
                [Project2].[CompanyId] AS [CompanyId], 
                [Limit1].[HistId] AS [HistId], 
                [Limit1].[UserID] AS [UserID], 
                [Limit1].[ProsID] AS [ProsID1], 
                [Limit1].[HDate] AS [HDate], 
                [Limit1].[ProsDocId] AS [ProsDocId]
                FROM   (SELECT 
                    @p__linq__0 AS [p__linq__0], 
                    [Distinct1].[ProsID] AS [ProsID], 
                    [Distinct1].[CompanyId] AS [CompanyId]
                    FROM ( SELECT DISTINCT 
                        [Extent1].[ProsID] AS [ProsID], 
                        [Extent2].[CompanyId] AS [CompanyId]
                        FROM  [dbo].[History] AS [Extent1]
                        INNER JOIN [dbo].[Prospectus] AS [Extent2] ON [Extent1].[ProsID] = [Extent2].[ProsId]
                        WHERE [Extent1].[UserID] = @p__linq__0
                    )  AS [Distinct1] ) AS [Project2]
                OUTER APPLY  (SELECT TOP (1) 
                    [Extent3].[HistId] AS [HistId], 
                    [Extent3].[UserID] AS [UserID], 
                    [Extent3].[ProsID] AS [ProsID], 
                    [Extent3].[HDate] AS [HDate], 
                    [Extent3].[ProsDocId] AS [ProsDocId]
                    FROM  [dbo].[History] AS [Extent3]
                    INNER JOIN [dbo].[Prospectus] AS [Extent4] ON [Extent3].[ProsID] = [Extent4].[ProsId]
                    WHERE ([Extent3].[UserID] = @p__linq__0) AND (([Project2].[CompanyId] = [Extent4].[CompanyId]) OR (1 = 0)) AND ([Project2].[ProsID] = [Extent3].[ProsID]) ) AS [Limit1]
            )  AS [Project4]
        )  AS [Project5]
    )  AS [Project6]
    ORDER BY [Project6].[C1] DESC

我的 Linq 查询显然有问题,这会导致 EF 产生这样的困惑。我以某种方式创建的 EF 查询效率不高吗?

最佳答案

每当分组发挥作用时,我更喜欢查询语法而不是流畅的语法。

当你做...

(
    from h in MyContext.HistoryItems
    where h.UserId == userId)
    group h by new { 
                        h.CompanyId, 
                        Comapany = h.Company.Name, 
                        Prospectus = h.Prospectus.Name, 
                        h.Prospectus.Online, 
                        h.ProsId 
                   } into grp
    select new { 
                    Max = grp.Max(i => i.Id),
                    grp.Key.CompanyId,
                    grp.Key.Comapany,
                    grp.Key.Prospectus,
                    grp.Key.Online,
                    grp.Key.ProsId,
               } into proj
    orderby proj.Max descending
    select proj
).Distinct().Take(10)

...查询应该更清晰,因为现在您只选择将出现在最终投影中的属性,并且 FirstOrDefault() 没有乱入。连接不均匀在那里,因为我让 EF 通过使用 h.Company 等导航属性来确定连接。

请注意,我试图重现 SQL 查询。 LINQ 查询对我来说看起来不像是同一件事。

关于c# - Entity Framework - Distinct 和 Max 生成巨大(且缓慢)的查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26147292/

相关文章:

c# - 将数字序列转换为范围

c# - 确定文本文件中使用的行结尾

mysql - 如何在字符串日期查询之间插入

mysql - sql 查询需要建议。需要统计某首歌在音乐节中播放的时间以及在决赛中获胜的次数

sql - 将 varchar 值 'Id' 转换为数据类型 int 时转换失败

c# - 调整表单宽度以匹配 SplitContainer 大小

c# - 批量命名空间重命名

MySQL的执行顺序

sql - 使用 IN 列表进行外部连接?

sql - += 在 SELECT 子句中;常数与列