为什么LINQ JOIN比用WHERE连接要快得多?

我最近升级到VS 2010,并与LINQ to Dataset玩弄。 我在ASP.NET WebApplication的HttpCache中有一个强大的Authorizationtypes数据集。

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

我已经检查了3种方法:

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

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

1.Iteration:

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

2.Iteration:

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

3.Iteration:

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

平均:

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

为什么Join-version比where语法要快得多,尽pipe作为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 

join:

 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的优势甚至比以前大很多:

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. join| 2.哪里

1.Iteration:

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

2.Iteration:

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

3.Iteration:

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

平均:

  1. join:0,0569367秒
  2. 其中:128251813秒

join速度快225倍

结论:避免WHERE指定关系,并尽可能使用JOIN(绝对在LINQ to DataSet和Linq-To-Objects中)。

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

  2. 具有多个表和Where条件的查询实际上执行所有表的笛卡尔乘积然后过滤满足条件的行。 这意味着Where条件针对每个行的组合(n1 * n2 * n3 * n4)

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

Join速度要快得多,因为该方法知道如何组合表格以将结果减less到相关的组合。 当您使用Where来指定关系时,必须创build每个可能的组合,然后testing条件以查看哪些组合是相关的。

Join方法可以设置一个散列表作为索引来快速将两个表压缩到一起,而Where方法在所有组合都已经创build之后运行,所以不能使用任何技巧来预先减less组合。

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

尽pipe你在这里分享的信息很棒。