Niedawno zaktualizowałem do VS 2010 i bawię się z LINQ to Dataset. Mam zestaw danych o silnym typie dla autoryzacji, który znajduje się w HttpCache aplikacji sieci Web ASP.NET.
Chciałem więc wiedzieć, jaki właściwie jest najszybszy sposób sprawdzenia, czy użytkownik jest upoważniony do zrobienia czegoś. Oto mój model danych i kilka innych informacji, jeśli ktoś jest zainteresowany.
Sprawdziłem 3 sposoby:
- bezpośrednia baza danych
- Zapytanie LINQ z warunkami Where jako „Join” - Składnia
- Zapytań LINQ z Dołącz - Składnia
Oto wyniki z 1000 wywołań dla każdej funkcji:
1. iteracja:
- 4,2841519 sek.
- 115,7796925, sek.
- 2,024749 sek.
2. iteracja:
- 3,1954857, sek.
- 84,97047 sek.
- 1,5783397, sek.
3. iteracja:
- 2,7922143, sek.
- 97,8713267 sek.
- 1,8432163, sek.
Średni:
- Baza danych: 3,4239506333 sek.
- Gdzie: 99,5404964 sek.
- Dołącz: 1,815435 sek.
Dlaczego wersja Join jest o wiele szybsza niż składnia where, co czyni ją bezużyteczną, chociaż jako nowicjusz LINQ wydaje się być najbardziej czytelna. A może przegapiłem coś w moich zapytaniach?
Oto zapytania LINQ, pomijam bazę danych:
Gdzie :
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
Przystąp:
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
Z góry dziękuję.
Edycja : po pewnych ulepszeniach obu zapytań w celu uzyskania bardziej znaczących wartości wydajności, przewaga JOIN jest nawet wielokrotnie większa niż wcześniej:
Dołącz :
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
Gdzie :
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
Wynik dla 1000 połączeń (na szybszym komputerze)
- Dołącz | 2. Gdzie
1. iteracja:
- 0,0713669 sek.
- 12,7395299 sek.
2. iteracja:
- 0,0492458 sek.
- 12,3885925 sek.
3. iteracja:
- 0,0501982, sek.
- 13,3474216 sek.
Średni:
- Dołącz: 0,0569367 sek.
- Gdzie: 12,8251813 sek.
Dołącz jest 225 razy szybciej
Wniosek: unikaj WHERE do określania relacji i używaj JOIN, gdy tylko jest to możliwe (zdecydowanie w LINQ to DataSet i Linq-To-Objectsogólnie).
Joinjakikolwiek sposób, po co polegać na optymalizatorze, skoro można napisać zoptymalizowany kod od początku? Sprawia również, że twoje intencje są jaśniejsze. Więc te same powody, dla których powinieneś preferować JOIN w sql .