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




2 Answers

  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

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. Here 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 possibile (in LINQ in modo preciso in DataSet e Linq-To-Objects in generale).




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ò.




Related

.net linq performance join linq-to-dataset