简体   繁体   English

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

[英]Entity Framework Order By Multiple Related Entity Count - Efficiency

So I have a Topic which has these related entities. 所以我有一个主题,有这些相关的实体。

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

I have the following query. 我有以下查询。 Where I want to pull out and order popular Topics based on the count of 3 related entities over a specific date period. 我希望在特定日期期间根据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();

I'm looking for the most efficient query for doing the above? 我正在寻找最有效的查询来做上述事情? Is what I am doing the best way to do this with EntityFramework? 我正在用EntityFramework做最好的方法吗? Or am I missing something? 或者我错过了什么?

Any help appreciated. 任何帮助赞赏。

If you put your above code into LINQPad , or check it with the profiler, you will see that it will probably generate something like the following SQL: 如果将上面的代码放入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

You could try rewriting the SQL a bit to GROUP the results of the subqueries and LEFT JOIN them to the original table, which does seem to be about 2x faster in the db itself: 您可以尝试将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

But getting LINQ to generate code like this is iffy at best. 但是让LINQ生成像这样的代码是最好的。 Doing LEFT JOIN s are not exactly its strong suit, and using the techniques that are out there for doing so will probably generate SQL that uses CROSS APPLY and/or OUTER APPLY instead, and will likely be as slow or slower than your current code. 执行LEFT JOIN并不是它的强项,并且使用这样做的技术可能会生成使用CROSS APPLY和/或OUTER APPLY SQL,并且可能会比当前代码慢或慢。

If you are that worried about speed, you might consider putting your fine-tuned SQL into a view so that you know that the query being used is the one you want. 如果您担心速度,可以考虑将经过微调的SQL放入视图中,以便您知道所使用的查询是您想要的查询。

Bear in mind, too, that you or someone else will have to come back to this code and maintain it later. 还要记住,您或其他人必须回到此代码并在以后维护它。 Your current linq statement is very straightforward and easy to understand. 您当前的linq语句非常简单易懂。 A complicated query is going to be harder to maintain and will take more work to alter in the future. 复杂的查询将难以维护,并且将来需要做更多的工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM