为什么LINQ JOIN比用WHERE连接要快得多?
我最近升级到VS 2010,并与LINQ to Dataset玩弄。 我在ASP.NET WebApplication的HttpCache中有一个强大的Authorizationtypes数据集。
所以我想知道什么是最快的方式来检查用户是否有权做一些事情。 这是我的数据模型和其他一些信息,如果有人感兴趣。
我已经检查了3种方法:
- 直接数据库
- 使用Where条件作为“join”的LINQ查询 – 语法
- 使用Join – Syntax的LINQ查询
这些是每个函数1000个调用的结果:
1.Iteration:
- 4,2841519秒
- 115,7796925秒
- 2,024749秒
2.Iteration:
- 3,1954857秒
- 84,97047秒
- 1,5783397秒
3.Iteration:
- 2,7922143秒
- 97,8713267秒
- 1,8432163秒
平均:
- 数据库:3,4239506333秒
- 其中:99,5404964秒
- 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个呼叫的结果(在更快的计算机上)
- join| 2.哪里
1.Iteration:
- 0,0713669秒
- 12,7395299秒
2.Iteration:
- 0,0492458秒
- 12,3885925秒
3.Iteration:
- 0,0501982秒
- 13,3474216秒
平均:
- join:0,0569367秒
- 其中:128251813秒
join速度快225倍
结论:避免WHERE指定关系,并尽可能使用JOIN(绝对在LINQ to DataSet和Linq-To-Objects
中)。
-
你的第一个方法(在数据库中的SQL查询)是非常有效的,因为数据库知道如何执行一个连接。 但是将其与其他方法进行比较并没有意义,因为它们直接在内存中工作(Linq到DataSet)
-
具有多个表和
Where
条件的查询实际上执行所有表的笛卡尔乘积 , 然后过滤满足条件的行。 这意味着Where
条件针对每个行的组合(n1 * n2 * n3 * n4) -
Join
运算符从第一个表中获取行,然后仅从第二个表中获取具有匹配键的行,然后仅从第三个表中获取具有匹配键的行,依此类推。 这样更有效率,因为它不需要执行很多操作
Join
速度要快得多,因为该方法知道如何组合表格以将结果减less到相关的组合。 当您使用Where
来指定关系时,必须创build每个可能的组合,然后testing条件以查看哪些组合是相关的。
Join
方法可以设置一个散列表作为索引来快速将两个表压缩到一起,而Where
方法在所有组合都已经创build之后运行,所以不能使用任何技巧来预先减less组合。
你真正需要知道的是为这两个语句创build的SQL。 有几种方法,但最简单的是使用LinqPad。 查询结果上方有几个button,将会更改为sql。 这会给你更多的信息比其他任何东西。
尽pipe你在这里分享的信息很棒。