实体框架按多个相关实体计数顺序 - 效率

时间:2015-03-13 07:05:42

标签: c# sql entity-framework linq-to-entities

所以我有一个包含这些相关实体的主题。

 - List<Posts>
 - List<Votes>
 - List<Views>

我有以下查询。我希望在特定日期期间根据3个相关实体的数量拉出并订购热门话题。

var topics = _context.Topic
.OrderByDescending(x => x.Posts.Count(c => c.DateCreated >= from && c.DateCreated <= to))
 .ThenByDescending(x => x.Votes.Count(c => c.DateCreated >= from && c.DateCreated <= to))
.ThenByDescending(x => x.Views.Count(c => c.DateCreated >= from && c.DateCreated <= to))
.Take(amountToShow)
.ToList();

我正在寻找最有效的查询来执行上述操作?我正在用EntityFramework做最好的方法吗?或者我错过了什么?

任何帮助表示感谢。

1 个答案:

答案 0 :(得分:2)

如果您将上述代码放入LINQPad,或者使用分析器进行检查,您会发现它可能会生成类似以下SQL的内容:

SELECT TOP @amountToShow [t0].[id] --and additional columns
FROM [Topic] AS [t0]
ORDER BY (
    SELECT COUNT(*)
    FROM [Posts] AS [t1]
    WHERE ([t1].DateCreated >= @from AND [t1].DateCreated <= @to) 
        AND ([t1].[topidId] = [t0].[id])
    ) DESC, (
    SELECT COUNT(*)
    FROM [Votes] AS [t2]
    WHERE ([t2].DateCreated >= @from AND [t2].DateCreated <= @to) 
        AND ([t2].[topicId] = [t0].[id])
    ) DESC , (
    SELECT COUNT(*)
    FROM [Views] AS [t3]
    WHERE ([t3].DateCreated >= @from AND [t3].DateCreated <= @to) 
        AND ([t3].[topicId] = [t0].[id])
    ) DESC
GO

您可以尝试将SQL重写为GROUP子查询的结果,并LEFT JOIN将它们重写到原始表中,这似乎在db本身中快了大约2倍:

SELECT TOP @amountToShow [t0].[id] --etc
FROM [Topic] AS [t0]
LEFT JOIN 
    (SELECT topicId, COUNT(*) AS num FROM Posts p 
    WHERE [p].DateCreated >= @from AND .DateCreated <= @to 
    GROUP BY topicId) [t1]
ON t0.id = t1.topicId
LEFT JOIN 
    (SELECT topicId, COUNT(*) AS num FROM Votes vo 
    WHERE [vo].DateCreated >= @from AND [vo].DateCreated <= @to 
    GROUP BY topidId) [t2]
ON t0.id = t2.topicId
LEFT JOIN 
    (SELECT topicId, COUNT(*) AS num FROM Views vi 
    WHERE [vi].DateCreated >= @from AND [vi].DateCreated <= @to 
    GROUP BY topicId) [t3]
ON t0.id = t3.topicId
ORDER BY t1.num DESC, t2.num DESC, t3.num DESC

但是让LINQ生成这样的代码是最好的。执行LEFT JOIN并不是它的强项,并且使用这样做的技术可能会生成使用CROSS APPLY和/或OUTER APPLY的SQL,而且很可能会比你当前的代码慢或慢。

如果您担心速度,可以考虑将经过微调的SQL放入视图中,以便您知道正在使用的查询是您想要的。

请记住,您或其他人必须回到此代码并在以后维护它。您当前的linq语句非常简单易懂。复杂的查询将难以维护,并且将来需要做更多的工作。