.net 为什么LINQ JOIN比链接WHERE快得多?

.net 为什么LINQ JOIN比链接WHERE快得多?,.net,linq,performance,join,linq-to-dataset,.net,Linq,Performance,Join,Linq To Dataset,我最近升级到VS2010,正在使用LINQtoDataSet。我有一个用于授权的强类型数据集,它位于ASP.NET Web应用程序的HttpCache中 所以我想知道检查用户是否被授权做某事的最快方法是什么。是我的数据模型和一些其他信息,如果有人感兴趣 我检查了3种方法: 直接数据库 使用Where条件作为“Join”语法的LINQ查询 使用连接的LINQ查询-语法 以下是对每个函数调用1000次的结果: 1.迭代: Public Function hasAccessDS_Join(ByVal

我最近升级到VS2010,正在使用LINQtoDataSet。我有一个用于授权的强类型数据集,它位于ASP.NET Web应用程序的HttpCache中

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

我检查了3种方法:

  • 直接数据库
  • 使用Where条件作为“Join”语法的LINQ查询
  • 使用连接的LINQ查询-语法
  • 以下是对每个函数调用1000次的结果:

    1.迭代:

    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
    
  • 42841519秒
  • 1157796925秒
  • 2024749秒
  • 2.迭代:

    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
    
  • 31954857秒
  • 8497047秒
  • 15783397秒
  • 3.迭代:

    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
    
  • 27922143秒
  • 978713267秒
  • 18432163秒
  • 平均值:

    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
    
  • 数据库:34239506333秒
  • 其中:995404964秒
  • 加入:1815435秒
  • 为什么Join版本比where语法快得多,这使得它毫无用处,尽管作为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
    
    先谢谢你


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

    加入

    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
    
    其中

    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次呼叫的结果(在速度更快的计算机上)
  • 加入| 2。在哪里
  • 1.迭代:

    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
    
  • 00713669秒
  • 127395299秒
  • 2.迭代:

    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
    
  • 00492458秒
  • 123885925秒
  • 3.迭代:

    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
    
  • 00501982秒
  • 133474216秒
  • 平均值:

    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
    
  • 加入:00569367秒
  • 其中:128251813秒

  • Join的速度快225倍


    结论:避免在哪里指定关系,并尽可能使用联接(一般而言,在和
    Linq to Objects
    中都是如此)。

    联接速度要快得多,因为该方法知道如何组合表以将结果减少到相关的组合中。使用
    Where
    指定关系时,必须创建每个可能的组合,然后测试条件以查看哪些组合相关


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

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

    不过你在那里分享了很多信息

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

  • 具有多个表和
    条件的查询,其中
    条件实际执行所有表的笛卡尔乘积,然后过滤满足该条件的行。这意味着对每个行组合(n1*n2*n3*n4)评估
    ,其中
    条件

  • Join
    操作符从第一个表中获取行,然后仅从第二个表中获取具有匹配键的行,然后仅从第三个表中获取具有匹配键的行,依此类推。这更有效,因为它不需要执行那么多操作


  • 非常感谢。编译器/运行时是否没有像dbms中那样的隐式优化?不应该不可能看出where关系实际上是一个连接。一个好的RDBMS应该确实发现where条件是对两个唯一列的相等性的测试,并将其视为一个连接。@Tim Schelter,当您使用Linq to SQL或Linq to Entities时,有这样一种优化,因为生成的SQL查询被DBMS视为联接。但在这种情况下,您使用Linq到数据集,没有到数据集的转换SQL@Tim:LINQ to数据集实际上使用LINQ to对象。因此,只有使用
    join
    关键字才能捕获真正的连接,因为没有对查询进行运行时分析来生成类似于执行计划的任何内容。您还会注意到,基于LINQ的联接只能容纳单列Equijoin。@Adam,这不完全正确:您可以使用匿名类型使用多个键进行Equijoin:
    。。。在new{f1.Key1,f1.Key2}上,等于new{f2.Key1,f2.Key2}
    感谢LinqPad提示。实际上,我的两个查询是linQ到数据集的内存查询,因此我假设没有生成SQL。通常情况下,数据库管理系统会对其进行优化。感谢您澄清背景。db方法并不是这个问题的一部分,但我很感兴趣地看到内存方法是否真的更快。我假设.net会以某种方式优化
    where
    -查询,就像dbms一样。实际上,
    JOIN
    的速度甚至比
    WHERE
    (上一次编辑)快225倍。对于阅读本文并正在使用LinqToSQL的其他人,如果他们认为更改所有连接位置可能会更好,请务必阅读THomas Levesque的评论,他在评论中说“当您使用Linq to SQL或Linq to Entities时,会有这样的优化,因为生成的SQL查询