3

在我的项目中,我使用 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' 效率低吗?

4

2 回答 2

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一次的行。

于 2013-07-26T20:56:03.173 回答
3

是的。当您执行计数时,您将选择与您的子句匹配的所有条目然后计数。使用 Any() 您的查询将在与该子句匹配的注册表的第一个标志处返回。我是我的选择,使用 Any() 总是比使用 count() 更好,除非你真的需要那个数字

于 2013-07-26T20:47:04.873 回答