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-Objects
ogólnie).
Join
jakikolwiek 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 .