Ho recentemente aggiornato a VS 2010 e sto giocando con LINQ to Dataset. Ho un set di dati tipizzato forte per l'autorizzazione che si trova in HttpCache di un'applicazione Web ASP.NET.
Quindi volevo sapere qual è effettivamente il modo più veloce per verificare se un utente è autorizzato a fare qualcosa. Ecco il mio modello di dati e alcune altre informazioni se qualcuno è interessato.
Ho verificato 3 modi:
- database diretto
- Query LINQ con condizioni Where come "Join" - Sintassi
- Query LINQ con Join - Sintassi
Questi sono i risultati con 1000 chiamate su ciascuna funzione:
1.Iterazione:
- 4.2841519 sec.
- 115,7796925 sec.
- 2.024749 sec.
2.Iterazione:
- 3.1954857 sec.
- 84,97047 sec.
- 1,5783397 sec.
3.Iterazione:
- 2,7922143 sec.
- 97,8713267 sec.
- 1,8432163 sec.
Media:
- Database: 3,4239506333 sec.
- Dove: 99,5404964 sec.
- Partecipa: 1.815435 sec.
Perché la versione Join è molto più veloce della sintassi where, il che la rende inutile anche se come principiante LINQ sembra essere la più leggibile. O mi sono perso qualcosa nelle mie domande?
Ecco le query LINQ, ignoro il database:
Dove :
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
Aderire:
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
Grazie in anticipo.
Modifica : dopo alcuni miglioramenti su entrambe le query per ottenere valori di prestazione più significativi, il vantaggio di JOIN è anche molte volte maggiore di prima:
Partecipa :
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
Dove :
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
Risultato per 1000 chiamate (su un computer più veloce)
- Partecipa | 2. Dove
1.Iterazione:
- 0,0713669 sec.
- 12,7395299 sec.
2.Iterazione:
- 0,0492458 sec.
- 12.3885925 sec.
3.Iterazione:
- 0,0501982 sec.
- 13.3474216 sec.
Media:
- Partecipa: 0,0569367 sec.
- Dove: 12,8251813 sec.
L'adesione è 225 volte più veloce
Conclusione: evitare WHERE per specificare le relazioni e utilizzare JOIN quando possibile (sicuramente in LINQ to DataSet e Linq-To-Objects
in generale).
Join
anywhy, perché affidarsi a un ottimizzatore se puoi scrivere il codice ottimizzato dall'inizio? Rende anche più chiare le tue intenzioni. Quindi gli stessi motivi per cui dovresti preferire JOIN in sql .