我最近升级到 VS 2010,并且正在使用 LINQ to Dataset。我有一个用于授权的强类型数据集,位于 ASP.NET Web 应用程序的 HttpCache 中。
所以我想知道检查用户是否有权执行某些操作的最快方法是什么。 Here是我的数据模型和一些其他信息(如果有人感兴趣)。
我检查了3种方法:
- 直接数据库
- 使用 Where 条件作为“Join”的 LINQ 查询 - 语法
- 使用 Join 进行 LINQ 查询 - 语法
以下是每个函数调用 1000 次的结果:
1.迭代:
- 4,2841519 秒
- 115,7796925 秒
- 2,024749 秒
2.迭代:
- 3,1954857 秒
- 84,97047 秒
- 1,5783397 秒
3.迭代:
- 2,7922143 秒
- 97,8713267 秒
- 1,8432163 秒
平均:
- 数据库:3,4239506333 秒
- 地点:99,5404964 秒
- 加入:1,815435 秒。
为什么 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
提前谢谢您。
<小时/>编辑:在对两个查询进行一些改进以获得更有意义的性能值之后,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 次调用的结果(在速度更快的计算机上)
- 加入 | 2. 地点
1.迭代:
- 0,0713669 秒
- 12,7395299 秒
2.迭代:
- 0,0492458 秒
- 12,3885925 秒
3.迭代:
- 0,0501982 秒。
- 13,3474216 秒
平均:
- 加入:0,0569367 秒。
- 地点:12,8251813 秒
加入速度快 225 倍
结论:避免在 WHERE 中指定关系,并尽可能使用 JOIN(通常在 LINQ to DataSet 和 Linq-To-Objects
中)。
最佳答案
您的第一种方法(数据库中的 SQL 查询)非常有效,因为数据库知道如何执行联接。但将其与其他方法进行比较并没有什么意义,因为它们直接在内存中工作(Linq to DataSet)
包含多个表和
Where
条件的查询实际上执行所有表的笛卡尔积,然后过滤行即满足条件。这意味着对每个行组合 (n1 * n2 * n3 * n4) 评估Where
条件Join
运算符从第一个表中获取行,然后仅从第二个表中获取具有匹配键的行,然后仅从第三个表中获取具有匹配键的行, 等等。这更加高效,因为它不需要执行那么多操作
关于.net - 为什么 LINQ JOIN 比 WHERE 链接快得多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5551264/