Dot-Net

為什麼 LINQ JOIN 比使用 WHERE 連結快得多?

  • April 5, 2011

我最近升級到 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一般情況下)。

  1. 您的第一種方法(數據庫中的 SQL 查詢)非常有效,因為數據庫知道如何執行連接。但是將它與其他方法進行比較並沒有什麼意義,因為它們直接在記憶體中工作(Linq to DataSet)
  2. 具有多個表和一個Where條件的查詢實際上執行所有表的笛卡爾積然後過濾滿足條件的行。這意味著Where針對每個行組合評估條件 (n1 * n2 * n3 * n4)
  3. 運算符從第Join一個表中獲取行,然後僅從第二個表中獲取具有匹配鍵的行,然後僅從第三個表中獲取具有匹配鍵的行,依此類推。這樣效率更高,因為它不需要執行那麼多操作

引用自:https://stackoverflow.com/questions/5551264