Ich habe kürzlich ein Upgrade auf VS 2010 durchgeführt und spiele mit LINQ to Dataset herum. Ich habe ein stark typisiertes Dataset für die Autorisierung, das sich in HttpCache einer ASP.NET-Webanwendung befindet.
Also wollte ich wissen, was eigentlich der schnellste Weg ist, um zu überprüfen, ob ein Benutzer berechtigt ist, etwas zu tun. Hier ist mein Datenmodell und einige andere Informationen, wenn jemand interessiert ist.
Ich habe 3 Möglichkeiten überprüft:
- Direkte Datenbank
- LINQ-Abfrage mit Where Bedingungen als "Join" - Syntax
- LINQ-Abfrage mit Join - Syntax
Dies sind die Ergebnisse mit 1000 Aufrufen für jede Funktion:
1.Iteration:
- 4,2841519 Sek.
- 115.7796925 Sek.
- 2,024749 Sek.
2.Iteration:
- 3,1954857 Sek.
- 84.97047 Sek.
- 1,5783397 Sek.
3.Iteration:
- 2,7922143 Sek.
- 97,8713267 sek.
- 1,8432163 Sek.
Durchschnittlich:
- Datenbank: 3,4239506333 Sek.
- Wo: 99.5404964 Sek.
- Beitritt: 1.815435 Sek.
Warum ist die Join-Version so viel schneller als die Where-Syntax, was sie unbrauchbar macht, obwohl sie als LINQ-Neuling am besten lesbar zu sein scheint. Oder habe ich etwas in meinen Fragen verpasst?
Hier sind die LINQ-Abfragen, ich überspringe die Datenbank:
Wo :
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
Beitreten:
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
Vielen Dank im Voraus.
Bearbeiten : Nach einigen Verbesserungen an beiden Abfragen, um aussagekräftigere Leistungswerte zu erhalten, ist der Vorteil von JOIN sogar um ein Vielfaches größer als zuvor:
Mitmachen :
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
Wo :
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
Ergebnis für 1000 Anrufe (auf einem schnelleren Computer)
- Beitreten | 2. Wo
1.Iteration:
- 0,0713669 Sek.
- 12.79595299 Sek.
2.Iteration:
- 0,0492458 Sek.
- 12.3885925 Sek.
3.Iteration:
- 0,0501982 Sek.
- 13.3474216 Sek.
Durchschnittlich:
- Beitritt: 0,0569367 Sek.
- Wo: 12.8251813 Sek.
Join ist 225-mal schneller
Schlussfolgerung: Vermeiden Sie, wo Beziehungen angegeben werden sollen, und verwenden Sie nach Möglichkeit JOIN (definitiv in LINQ to DataSet und Linq-To-Objects
allgemein).
quelle
Join
irgendetwas zu verwenden . Warum sollten Sie sich auf ein Optimierungsprogramm verlassen, wenn Sie den optimierten Code von Anfang an schreiben können? Es macht auch Ihre Absichten klarer. Also die gleichen Gründe, warum Sie JOIN in SQL bevorzugen sollten .Antworten:
Ihr erster Ansatz (SQL-Abfrage in der Datenbank) ist sehr effizient, da die Datenbank weiß, wie ein Join ausgeführt wird. Es ist jedoch nicht wirklich sinnvoll, es mit den anderen Ansätzen zu vergleichen, da sie direkt im Speicher arbeiten (Linq to DataSet).
Die Abfrage mit mehreren Tabellen und einer
Where
Bedingung führt tatsächlich ein kartesisches Produkt aller Tabellen aus und filtert dann die Zeilen, die die Bedingung erfüllen. Dies bedeutet, dass dieWhere
Bedingung für jede Kombination von Zeilen ausgewertet wird (n1 * n2 * n3 * n4).Der
Join
Operator nimmt die Zeilen aus den ersten Tabellen, dann nur die Zeilen mit einem übereinstimmenden Schlüssel aus der zweiten Tabelle, dann nur die Zeilen mit einem übereinstimmenden Schlüssel aus der dritten Tabelle und so weiter. Dies ist viel effizienter, da nicht so viele Vorgänge ausgeführt werden müssenquelle
where
Abfrage in gewisser Weise genauso wie eine Datenbank optimieren würde . EigentlichJOIN
war das sogar 225 mal schneller als dasWHERE
(letzte Bearbeitung).Das
Join
ist viel schneller, weil die Methode weiß , wie man die Tabellen zu kombinieren , um das Ergebnis zu den entsprechenden Kombinationen zu reduzieren. Wenn SieWhere
die Beziehung angeben, muss jede mögliche Kombination erstellt und anschließend die Bedingung getestet werden, um festzustellen, welche Kombinationen relevant sind.Die
Join
Methode kann eine Hash-Tabelle einrichten, die als Index verwendet wird, um zwei Tabellen schnell zusammen zu komprimieren, während dieWhere
Methode ausgeführt wird, nachdem alle Kombinationen bereits erstellt wurden. Daher kann sie keine Tricks verwenden, um die Kombinationen im Voraus zu reduzieren.quelle
join
Schlüsselwort erfasst werden , da es keine Laufzeitanalyse der Abfrage gibt, um etwas Analoges zu einem Ausführungsplan zu erstellen. Sie werden auch feststellen, dass LINQ-basierte Joins nur einspaltige Equijoins aufnehmen können.... on new { f1.Key1, f1.Key2 } equals new { f2.Key1, f2.Key2 }
Was Sie wirklich wissen müssen, ist die SQL, die für die beiden Anweisungen erstellt wurde. Es gibt einige Möglichkeiten, um dorthin zu gelangen, aber die einfachste ist die Verwendung von LinqPad. Direkt über den Abfrageergebnissen befinden sich mehrere Schaltflächen, die in SQL geändert werden. Das gibt Ihnen viel mehr Informationen als alles andere.
Tolle Informationen, die Sie dort geteilt haben.
quelle