C# Linq语句中的“let”生成交叉联接
考虑以下linq声明C# Linq语句中的“let”生成交叉联接,c#,sql-server,entity-framework,linq,C#,Sql Server,Entity Framework,Linq,考虑以下linq声明 var users = from a in dbContext.Users select a; var list = (from a in users let count = users.Count() where a.IsActive == true select new { a.UserId, count }).ToList(); 如果我们检查这个linq语句的
var users = from a in dbContext.Users
select a;
var list = (from a in users
let count = users.Count()
where a.IsActive == true
select new { a.UserId, count }).ToList();
如果我们检查这个linq语句的探查器,它会显示交叉连接以获取每个记录的计数
SELECT
[Extent1].[UserId] AS [UserId],
[GroupBy1].[A1] AS [C1]
FROM [dbo].[Users] AS [Extent1]
CROSS JOIN (SELECT
COUNT(1) AS [A1]
FROM [dbo].[Users] AS [Extent2] ) AS [GroupBy1]
WHERE 1 = [Extent1].[IsActive]
我认为sql语句的交叉连接开销可能会导致记录数量巨大时的性能问题
作为一种解决方案,我可以移动这些数据。在linq语句之外进行计数,然后放入select,但这会导致两db的操作
var count = (from a in dbContext.Users
select a).Count();
var list = (from a in dbContext.Users
where a.IsActive == true
select new { a.UserId, count }).ToList();
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[Users] AS [Extent1]
) AS [GroupBy1]
exec sp_executesql N'SELECT
[Extent1].[UserId] AS [UserId],
@p__linq__0 AS [C1]
FROM [dbo].[Users] AS [Extent1]
WHERE 1 = [Extent1].[IsActive]',N'@p__linq__0 int',@p__linq__0=26
通过查看分析器,它将生成以下两个操作
var count = (from a in dbContext.Users
select a).Count();
var list = (from a in dbContext.Users
where a.IsActive == true
select new { a.UserId, count }).ToList();
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[Users] AS [Extent1]
) AS [GroupBy1]
exec sp_executesql N'SELECT
[Extent1].[UserId] AS [UserId],
@p__linq__0 AS [C1]
FROM [dbo].[Users] AS [Extent1]
WHERE 1 = [Extent1].[IsActive]',N'@p__linq__0 int',@p__linq__0=26
有谁能有比这更好的解决办法吗。或者,有谁能建议将let放入linq或之前获取它的最佳方法吗?生成的sql不应该有任何性能问题。交叉连接会产生一条记录,无论表中有多少活动用户,优化器只需计算一次 如果您不确信,请将执行计划与您的备选方案进行比较。我只能考虑使用子选择,但在我看来并不是更好 子选择 我认为sql语句的交叉连接开销可能会导致记录数量巨大时的性能问题 不一定。请注意,这是连接到一个子查询,该子查询是数据计数的单行/列。您可以用不同的方式编写此查询,但最终,它需要加入以返回{UserId,count}。如果没有联接,则无法返回该数据。它现在所做的连接非常有效。因此,我建议不要尝试优化您没有的问题,即过早优化 更新:添加实际执行计划请参见以下查询。您可以看到它连接到一个标量值,例如只运行一次Count select查询 查询:
SELECT
[Extent1].[UserId] AS [UserId],
[GroupBy1].[A1] AS [C1]
FROM [dbo].[Users] AS [Extent1]
CROSS JOIN (SELECT
COUNT(1) AS [A1]
FROM [dbo].[Users] AS [Extent2] ) AS [GroupBy1]
WHERE 1 = [Extent1].[IsActive]
执行计划:
数据是如何声明的?您使用的是哪个版本的EF?我使用的是EF 6和.Net Framework 4.5。@JenishRabadiya:是的。它还生成交叉联接。同意,但您不认为下面的语句在联接中生成了同样多的select语句吗。i、 将执行select语句10倍以上的E10条记录。交叉连接将COUNT1从[dbo]选择为[A1]。[Users]选择为[Extent2]选择为[GroupBy1]@HarshadVekariya不,不应该。更新了答案以向您展示示例执行计划。请注意,它计算一个标量值计数,并将另一个查询与该标量值连接起来,只运行一次计数查询。感谢您发布执行计划,但如果您检查它,它将占用总执行量的近50%。@HarshadVekariya这是一件好事。它必须扫描两次:一次用于计数,另一次用于另一个查询。如果它必须对每一个用户都进行扫描,那么它将超过50%。