101

我最近升级到 VS 2010 并且正在使用 LINQ to Dataset。我有一个强类型的授权数据集,位于 ASP.NET WebApplication 的 HttpCache 中。

所以我想知道检查用户是否被授权做某事的最快方法实际上是什么。如果有人感兴趣,这是我的数据模型和其他一些信息。

我检查了3种方法:

  1. 直接数据库
  2. 使用Where条件作为“加入”的LINQ 查询- 语法
  3. 使用Join的 LINQ 查询- 语法

这些是每个函数调用 1000 次的结果:

1.迭代:

  1. 4,2841519 秒。
  2. 115,7796925 秒。
  3. 2,024749 秒。

2.迭代:

  1. 3,1954857 秒。
  2. 84,97047 秒。
  3. 1,5783397 秒。

3.迭代:

  1. 2,7922143 秒。
  2. 97,8713267 秒。
  3. 1,8432163 秒。

平均的:

  1. 数据库:3,4239506333 秒。
  2. 其中:99,5404964 秒。
  3. 加入:1,815435 秒。

为什么 Join-version 比 where-syntax 快得多,这使得它毫无用处,尽管作为 LINQ 新手,它似乎是最易读的。还是我在查询中遗漏了什么?

这是 LINQ 查询,我跳过了数据库:

哪里

Public Function hasAccessDS_Where(ByVal accessRule As String) As Boolean
    Dim userID As Guid = DirectCast(Membership.GetUser.ProviderUserKey, Guid)
    Dim query = From accRule In Authorization.dsAuth.aspnet_AccessRule, _
                roleAccRule In Authorization.dsAuth.aspnet_RoleAccessRule, _
                role In Authorization.dsAuth.aspnet_Roles, _
                userRole In Authorization.dsAuth.aspnet_UsersInRoles _
                Where accRule.idAccessRule = roleAccRule.fiAccessRule _
                And roleAccRule.fiRole = role.RoleId _
                And userRole.RoleId = role.RoleId _
                And userRole.UserId = userID And accRule.RuleName.Contains(accessRule)
                Select accRule.idAccessRule
    Return query.Any
End Function

加入:

Public Function hasAccessDS_Join(ByVal accessRule As String) As Boolean
    Dim userID As Guid = DirectCast(Membership.GetUser.ProviderUserKey, Guid)
    Dim query = From accRule In Authorization.dsAuth.aspnet_AccessRule _
                Join roleAccRule In Authorization.dsAuth.aspnet_RoleAccessRule _
                On accRule.idAccessRule Equals roleAccRule.fiAccessRule _
                Join role In Authorization.dsAuth.aspnet_Roles _
                On role.RoleId Equals roleAccRule.fiRole _
                Join userRole In Authorization.dsAuth.aspnet_UsersInRoles _
                On userRole.RoleId Equals role.RoleId _
                Where userRole.UserId = userID And accRule.RuleName.Contains(accessRule)
                Select accRule.idAccessRule
    Return query.Any
End Function

先感谢您。


编辑:在对两个查询进行一些改进以获得更有意义的性能值之后,JOIN 的优势甚至比以前大很多倍:

加入

Public Overloads Shared Function hasAccessDS_Join(ByVal userID As Guid, ByVal idAccessRule As Int32) As Boolean
    Dim query = From accRule In Authorization.dsAuth.aspnet_AccessRule _
                   Join roleAccRule In Authorization.dsAuth.aspnet_RoleAccessRule _
                   On accRule.idAccessRule Equals roleAccRule.fiAccessRule _
                   Join role In Authorization.dsAuth.aspnet_Roles _
                   On role.RoleId Equals roleAccRule.fiRole _
                   Join userRole In Authorization.dsAuth.aspnet_UsersInRoles _
                   On userRole.RoleId Equals role.RoleId _
                   Where accRule.idAccessRule = idAccessRule And userRole.UserId = userID
             Select role.RoleId
    Return query.Any
End Function

哪里

Public Overloads Shared Function hasAccessDS_Where(ByVal userID As Guid, ByVal idAccessRule As Int32) As Boolean
    Dim query = From accRule In Authorization.dsAuth.aspnet_AccessRule, _
           roleAccRule In Authorization.dsAuth.aspnet_RoleAccessRule, _
           role In Authorization.dsAuth.aspnet_Roles, _
           userRole In Authorization.dsAuth.aspnet_UsersInRoles _
           Where accRule.idAccessRule = roleAccRule.fiAccessRule _
           And roleAccRule.fiRole = role.RoleId _
           And userRole.RoleId = role.RoleId _
           And accRule.idAccessRule = idAccessRule And userRole.UserId = userID
           Select role.RoleId
    Return query.Any
End Function

1000 次呼叫的结果(在更快的计算机上)

  1. 加入 | 2. 在哪里

1.迭代:

  1. 0,0713669 秒。
  2. 12,7395299 秒。

2.迭代:

  1. 0,0492458 秒。
  2. 12,3885925 秒。

3.迭代:

  1. 0,0501982 秒。
  2. 13,3474216 秒。

平均的:

  1. 加入:0,0569367 秒。
  2. 其中:12,8251813 秒。

加入速度快 225 倍

结论:尽可能避免 WHERE 指定关系并使用 JOIN(绝对是在LINQ to DataSetLinq-To-Objects一般情况下)。

4

3 回答 3

78
  1. 您的第一种方法(数据库中的 SQL 查询)非常有效,因为数据库知道如何执行连接。但是将它与其他方法进行比较并没有什么意义,因为它们直接在内存中工作(Linq to DataSet)

  2. The query with multiple tables and a Where condition actually performs a cartesian product of all the tables, then filters the rows that satisfy the condition. This means the Where condition is evaluated for each combination of rows (n1 * n2 * n3 * n4)

  3. The Join operator takes the rows from the first tables, then takes only the rows with a matching key from the second table, then only the rows with a matching key from the third table, and so on. This is much more efficient, because it doesn't need to perform as many operations

于 2011-04-05T12:06:20.487 回答
19

Join更快,因为该方法知道如何组合表格以将结果减少到相关组合。当您使用Where指定关系时,它必须创建每个可能的组合,然后测试条件以查看哪些组合是相关的。

Join方法可以设置一个哈希表作为索引,将两个表快速压缩在一起,而该Where方法在所有组合都已创建后运行,因此无法使用任何技巧来预先减少组合。

于 2011-04-05T11:56:14.397 回答
7

您真正需要知道的是为这两个语句创建的 sql。有几种方法可以使用,但最简单的是使用 LinqPad。查询结果正上方有几个按钮将更改为 sql。这将为您提供比其他任何东西更多的信息。

不过,你在那里分享的信息很好。

于 2011-04-05T11:56:50.957 回答