所以我有一个包含这些相关实体的主题。
- 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做最好的方法吗?或者我错过了什么?
任何帮助表示感谢。
答案 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语句非常简单易懂。复杂的查询将难以维护,并且将来需要做更多的工作。