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


Answers

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

Question

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