Perché LINQ JOIN è molto più veloce del collegamento con DOVE?

Ho recentemente aggiornato a VS 2010 e sto giocando con LINQ to Dataset. Ho un dataset tipizzato forte per Autorizzazione che si trova in HttpCache di un’applicazione Web ASP.NET.

Quindi volevo sapere qual è in realtà il modo più veloce per verificare se un utente è autorizzato a fare qualcosa. Ecco il mio datamodel e alcune altre informazioni se qualcuno è interessato.

Ho controllato 3 modi:

  1. database diretto
  2. Query LINQ con condizioni Where come “Join” – Sintassi
  3. Query LINQ con Join – Sintassi

Questi sono i risultati con 1000 chiamate su ciascuna funzione:

1.Iteration:

  1. 4,2841519 sec.
  2. 115,7796925 sec.
  3. 2,024749 sec.

2.Iteration:

  1. 3,1954857 sec.
  2. 84.97047 sec.
  3. 1,5783397 sec.

3.Iteration:

  1. 2,7922143 sec.
  2. 97,8713267 sec.
  3. 1,8432163 sec.

Media:

  1. Database: 3,4239506333 sec.
  2. Dove: 99,5404964 sec.
  3. Iscriviti: 1,815435 sec.

Perché la versione Join è molto più veloce della Where-Syntax che la rende inutilizzabile anche se come novizio LINQ sembra essere la più leggibile. O ho perso qualcosa nelle mie domande?

Ecco le query LINQ, salta 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 perfomance più significativi, il vantaggio di JOIN è anche molte volte maggiore di prima:

Iscriviti :

 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)

  1. Partecipa | 2. Dove

1.Iteration:

  1. 0,0713669 sec.
  2. 12,7395299 sec.

2.Iteration:

  1. 0,0492458 sec.
  2. 12,3885925 sec.

3.Iteration:

  1. 0,0501982 sec.
  2. 13,3474216 sec.

Media:

  1. Iscriviti: 0,0569367 sec.
  2. Dove: 12,8251813 sec.

Unisciti è 225 volte più veloce

Conclusione: evitare DOVE specificare le relazioni e utilizzare JOIN quando ansible (in LINQ in modo preciso in DataSet e Linq-To-Objects in generale).

  1. Il tuo primo approccio (query SQL nel DB) è abbastanza efficiente perché il DB sa come eseguire un join. Ma non ha senso confrontarlo con gli altri approcci, dal momento che lavorano direttamente in memoria (da Linq a DataSet)

  2. La query con più tabelle e una condizione Where esegue effettivamente un prodotto cartesiano di tutte le tabelle, quindi filtra le righe che soddisfano la condizione. Ciò significa che la condizione Where viene valutata per ciascuna combinazione di righe (n1 * n2 * n3 * n4)

  3. L’operatore Join accetta le righe dalle prime tabelle, quindi accetta solo le righe con una chiave corrispondente dalla seconda tabella, quindi solo le righe con una chiave corrispondente dalla terza tabella e così via. Questo è molto più efficiente, perché non ha bisogno di eseguire tante operazioni

L’ Join è molto più veloce, perché il metodo sa come combinare le tabelle per ridurre il risultato alle combinazioni pertinenti. Quando si utilizza Where specificare la relazione, deve creare ogni combinazione ansible e quindi verificare la condizione per vedere quali combinazioni sono rilevanti.

Il metodo Join può impostare una tabella hash da utilizzare come indice per comprimere rapidamente due tabelle insieme, mentre il metodo Where viene eseguito dopo che tutte le combinazioni sono già state create, quindi non può utilizzare alcun trucco per ridurre le combinazioni in anticipo.

quello che devi veramente sapere è lo sql che è stato creato per le due affermazioni. Ci sono alcuni modi per arrivarci, ma il più semplice è usare LinqPad. Ci sono diversi pulsanti proprio sopra i risultati della query che cambieranno in sql. Questo ti darà molte più informazioni di ogni altra cosa.

Grandi informazioni che hai condiviso lì però.