J'ai récemment mis à niveau vers VS 2010 et je joue avec LINQ to Dataset. J'ai un ensemble de données fortement typé pour l'autorisation qui se trouve dans HttpCache d'une application Web ASP.NET.
Je voulais donc savoir quel est en fait le moyen le plus rapide de vérifier si un utilisateur est autorisé à faire quelque chose. Voici mon datamodel et quelques autres informations si quelqu'un est intéressé.
J'ai vérifié 3 façons:
- base de données directe
- Requête LINQ avec des conditions Where comme "Join" - Syntaxe
- Requête LINQ avec Join - Syntaxe
Voici les résultats avec 1000 appels sur chaque fonction:
1. itération:
- 4,2841519 sec.
- 115,7796925 sec.
- 2,024749 sec.
2. itération:
- 3,1954857 sec.
- 84 97047 sec.
- 1,5783397 sec.
3. itération:
- 2,7922143 sec.
- 97,8713267 sec.
- 1,8432163 sec.
Moyenne:
- Base de données: 3,4239506333 sec.
- Où: 99,5404964 sec.
- Rejoindre: 1,815435 sec.
Pourquoi la version Join est-elle tellement plus rapide que la syntaxe where, ce qui la rend inutile alors qu'en tant que débutant LINQ, elle semble être la plus lisible. Ou ai-je manqué quelque chose dans mes requêtes?
Voici les requêtes LINQ, je saute la base de données:
Où :
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
Joindre:
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
Merci d'avance.
Edit : après quelques améliorations sur les deux requêtes pour obtenir des valeurs de performance plus significatives, l'avantage du JOIN est même plusieurs fois plus important qu'avant:
Rejoindre :
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
Où :
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
Résultat pour 1000 appels (sur un ordinateur plus rapide)
- Rejoindre | 2. Où
1. itération:
- 0,0713669 sec.
- 12,7395299 sec.
2. itération:
- 0,0492458 sec.
- 12,3885925 sec.
3. itération:
- 0,0501982 sec.
- 13,3474216 sec.
Moyenne:
- Joindre: 0,0569367 sec.
- Où: 12,8251813 sec.
L'adhésion est 225 fois plus rapide
Conclusion: évitez WHERE de spécifier des relations et utilisez JOIN dans la mesure du possible (certainement dans LINQ to DataSet et Linq-To-Objects
en général).
Join
anywhy, pourquoi compter sur un optimiseur si vous pouvez écrire le code optimisé depuis le début? Cela rend également vos intentions plus claires. Donc, les mêmes raisons pour lesquelles vous devriez préférer JOIN en sql .