我最近升级到了VS 2010,正在玩LINQ to Dataset。我有一个强大的类型化的Authorization数据集,它位于ASP.NET WebApplication的HttpCache中。
所以我想知道实际上检查用户是否有权做某事的最快方法。如果有人感兴趣,Here是我的数据模型和其他一些信息。
我检查了3种方法:
这些是每个函数1000次调用的结果:
1.Iteration:
2.Iteration:
3.Iteration:
平均:
为什么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
1.Iteration:
2.Iteration:
3.Iteration:
平均:
加入速度快了225倍
结论:避免WHERE指定关系并尽可能使用JOIN(通常在LINQ to DataSet和Linq-To-Objects
中)。
答案 0 :(得分:74)
您的第一种方法(数据库中的SQL查询)非常高效,因为数据库知道如何执行连接。但是将它与其他方法进行比较并没有多大意义,因为它们直接在内存中工作(Linq to DataSet)
包含多个表和Where
条件的查询实际上执行了所有表的笛卡尔积,然后过滤满足条件。这意味着为每个行组合评估Where
条件(n1 * n2 * n3 * n4)
Join
运算符从第一个表中获取行,然后仅从第二个表中获取具有匹配键的行,然后仅获取第三个表中具有匹配键的行,等等上。这样效率更高,因为它不需要执行任何操作
答案 1 :(得分:19)
Join
要快得多,因为该方法知道如何组合表以将结果减少到相关组合。当您使用Where
指定关系时,它必须创建所有可能的组合,然后测试条件以查看哪些组合是相关的。
Join
方法可以设置一个哈希表,用作快速压缩两个表的索引,而Where
方法在所有组合已经创建后运行,所以它不能使用任何技巧预先减少组合。
答案 2 :(得分:7)
你真正需要知道的是为这两个语句创建的sql。有几种方法可以实现,但最简单的方法是使用LinqPad。查询结果正上方有几个按钮将更改为sql。这将为您提供比其他任何信息更多的信息。
你在那里分享了很棒的信息。