在我的项目中,我使用Entity Framework 4.4.0.0,我遇到了以下困境。我必须检查用户是否被激活。我的查询如下:
任何()
_context.Users.Any(u => u.Id == userId && u.IsActivated);
生成的sql是:
SELECT CASE
WHEN ( EXISTS (SELECT 1 AS [C1]
FROM [dbo].[Users] AS [Extent1]
WHERE ( [Extent1].[Id] = @p__linq__0 )
AND ( [Extent1].[IsActivated] = 1 )) ) THEN cast(1 AS BIT)
WHEN ( NOT EXISTS (SELECT 1 AS [C1]
FROM [dbo].[Users] AS [Extent2]
WHERE ( [Extent2].[Id] = @p__linq__0 )
AND ( [Extent2].[IsActivated] = 1 )) ) THEN cast(0 AS BIT)
END AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable1]
Count()
我收到此查询:
SELECT [GroupBy1].[A1] AS [C1]
FROM (SELECT COUNT(1) AS [A1]
FROM [dbo].[Users] AS [Extent1]
WHERE ( [Extent1].[Id] = @p__linq__0 )
AND ( [Extent1].[IsActivated] = 1 )) AS [GroupBy1]
这看起来不错吗?我不是很好sql ...但它对我来说效率不高。我错过了什么吗?
“select count(*) from dbo.Users where id=@id and IsActivated=1
”的效率会降低吗?
答案 0 :(得分:5)
取决于。
EXISTS
实施也不是那么好。如果有0
行,它将执行两次检查。在这种情况下,COUNT
一个会更好,因为它只需要搜索不存在的行并计算一次。
您可能会发现检查
_context.Users
.Where(u => u.Id == userId && u.IsActivated)
.Select(u=> true)
.FirstOrDefault();
给出了比两者更好的计划(根据卢克的建议修改)。在EF4上测试生成的查询是按照
的方式进行的SELECT TOP (1) cast(1 AS BIT) AS [C1]
FROM Users
WHERE userId = @userId
AND IsActivated = 1
如果存在多个行,并且仅执行与WHERE
匹配的行搜索,则不会处理不必要的额外行。
答案 1 :(得分:3)
是的。 执行计数时,您将选择与您的子句匹配的所有条目,然后计数。使用Any(),您的查询将返回与该子句匹配的注册表的第一个符号。 我是我的选择,使用Any()而不是count()总是更好,除非你真的需要那个数字