考虑遵循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语句的交叉连接开销,并且当记录数量巨大时可能会导致性能问题。
作为一个解决方案,我可以将data.Count()
移到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
任何人都可以有比这更好的解决方案。或者,任何人都可以建议最好的方法让让我们进入linq或之前获得它?
答案 0 :(得分:2)
生成的sql不应该有任何性能问题。交叉连接产生一条记录,优化器只需计算一次,无论表中的活动用户数量多少。
如果您不相信将执行计划与您的替代计划进行比较。我只能想到使用子选择,但它对我来说并不好看。
子选择
SELECT
[UserId],
(SELECT count(*) FROM [dbo].[Users]) as [Cnt]
FROM [dbo].[Users]
WHERE 1 = [IsActive]
答案 1 :(得分:2)
我认为sql语句的交叉连接开销,并且当记录数量巨大时可能会导致性能问题。
不一定。请注意,这是一个子查询,它是一行/一列数据(计数)。您可以用不同的方式编写此查询,但最终,需要加入才能返回{UserId,count}
。没有连接,您无法返回该数据。它现在正在进行的加入非常有效。因此,我建议不尝试优化您不会遇到的问题(即过早优化)。
更新:为以下查询添加实际执行计划(请参阅how to)。您可以看到它正在加入标量值(例如,只运行一次Count选择查询)。
查询:
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]