Kraft Entity Framework SQL-Parametrisierung für bessere SQL-proc-cache Wiederverwendung
Entity Framework scheint immer die Konstanten verwenden, die in der generierten SQL für die Werte bereitgestellt werden, um Skip()
und Take()
.
In der ultra-Vereinfachtes Beispiel unten:
int x = 10;
int y = 10;
var stuff = context.Users
.OrderBy(u => u.Id)
.Skip(x)
.Take(y)
.Select(u => u.Id)
.ToList();
x = 20;
var stuff2 = context.Users
.OrderBy(u => u.Id)
.Skip(x)
.Take(y)
.Select(u => u.Id)
.ToList();
der obige code erzeugt die folgenden SQL-Abfragen:
SELECT TOP (10)
[Extent1].[Id] AS [Id]
FROM ( SELECT [Extent1].[Id] AS [Id], row_number() OVER (ORDER BY [Extent1].[Id] ASC) AS [row_number]
FROM [dbo].[User] AS [Extent1]
) AS [Extent1]
WHERE [Extent1].[row_number] > 10
ORDER BY [Extent1].[Id] ASC
SELECT TOP (10)
[Extent1].[Id] AS [Id]
FROM ( SELECT [Extent1].[Id] AS [Id], row_number() OVER (ORDER BY [Extent1].[Id] ASC) AS [row_number]
FROM [dbo].[User] AS [Extent1]
) AS [Extent1]
WHERE [Extent1].[row_number] > 20
ORDER BY [Extent1].[Id] ASC
Was in 2 ad-hoc-Pläne Hinzugefügt, um die SQL-proc-cache mit 1 Einsatz jeder.
Was ich möchte, zu erreichen, ist für die Parametrisierung der Skip()
und Take()
Logik, damit die folgenden SQL-Abfragen generiert:
EXEC sp_executesql N'SELECT TOP (@p__linq__0)
[Extent1].[Id] AS [Id]
FROM ( SELECT [Extent1].[Id] AS [Id], row_number() OVER (ORDER BY [Extent1].[Id] ASC) AS [row_number]
FROM [dbo].[User] AS [Extent1]
) AS [Extent1]
WHERE [Extent1].[row_number] > @p__linq__1
ORDER BY [Extent1].[Id] ASC',N'@p__linq__0 int,@p__linq__1 int',@p__linq__0=10,@p__linq__1=10
EXEC sp_executesql N'SELECT TOP (@p__linq__0)
[Extent1].[Id] AS [Id]
FROM ( SELECT [Extent1].[Id] AS [Id], row_number() OVER (ORDER BY [Extent1].[Id] ASC) AS [row_number]
FROM [dbo].[User] AS [Extent1]
) AS [Extent1]
WHERE [Extent1].[row_number] > @p__linq__1
ORDER BY [Extent1].[Id] ASC',N'@p__linq__0 int,@p__linq__1 int',@p__linq__0=10,@p__linq__1=20
Diese Ergebnisse in 1 Vorbereiteten plan Hinzugefügt, um die SQL-proc-cache mit 2 verwendet.
Habe ich einige ziemlich komplexe Abfragen und erlebe erheblichen overhead (auf der Seite SQL Server) auf dem ersten Lauf, und viel schnellere Ausführung auf die nachfolgende ausgeführt wird (da Sie es verwenden können, der plan cache). Beachten Sie, dass diese erweiterte Abfragen bereits verwenden von sp_executesql als die anderen Werte werden parametriert, so bin ich nicht besorgt über diesen Aspekt.
Den ersten Satz von generierten Abfragen über grundsätzlich bedeutet jede Paginierung Logik erstellt einen neuen Eintrag in der plan-cache für jede Seite, Blähungen den cache und die plan-Generierung Gemeinkosten werden die Kosten für jede Seite.
Kann ich Kraft Entity Framework zur Parametrisierung der Werte? Ich habe bemerkt, für andere Werte, z.B. in Where
Klauseln, manchmal ist es parametrisiert Werte, und manchmal ist es verwendet Konstanten.
Bin ich völlig out to lunch? Gibt es einen Grund, warum Entity Framework vorhandene Verhalten besser als das Verhalten, das ich mir Wünsche?
Edit:
Falls es relevant ist, ich sollte erwähnen, dass ich mit Entity Framework 4.2.
Edit 2:
Diese Frage ist nicht ein Duplikat von Entity Framework/Linq to SQL: Skip & Nehmen, die lediglich fragt, wie um sicherzustellen, dass Skip
und Take
ausführen, die in SQL statt auf dem client. Diese Frage bezieht sich auf die Parametrisierung dieser Werte.
- Dieser link erklärt, wie Sie mithilfe von Linq-mit SQL-Parametern Sie müssen nach unten scrollen, um den unteren link, um zu sehen, die Erklärung und Beispiel LinqPad-site - linqpad.net/WhyLINQBeatsSQL.aspx
- Tolle Beobachtung. Ich normalerweise nicht verwenden, EF-für "echte" Projekte, die nur spielen, um mit kleinen Sachen, und nie bemerkt, dass dieses Verhalten vor. Wenn EF nicht parametrisieren alles, was es kann, dann ich halte das für einen riesigen Fehler.
- gute Frage - man könnte meinen, Sie hatte optimiert für eine mögliche Wiederverwendung des plans
- KRAZE: dein link erklärt, dass Linq kann die Verwendung von parametrisierten SQL, aber es gibt nichts über Steuern, wenn es passiert.
- Ich entschuldige mich über das GWB habe ich deine Frage missverstanden..
- Mögliche Duplikate von Entity Framework/Linq to SQL: Skip & Take
- der verlinkte Frage ist anders, als es nur verlangt, um sicherzustellen, dass die Take-und Skip-Ausführung auf der Datenbank statt auf dem client. Es geht nicht, der zusätzliche Schritt ist, sicherzustellen, dass die Take-und Skip verwenden Sie die Parametrierung für proc cache wiederverwenden.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Update: Skip und Take Verlängerung Methoden, die lambda-Parameter, die unten beschrieben sind, sind Teil von Entity Framework ab version 6 und höher). Sie können nutzen Sie die durch den Import der System.Daten.Entity-namespace im code.
Im Allgemeinen LINQ to Entities übersetzt Konstanten als Konstanten und Variablen an die Abfrage übergeben in die Parameter.
Das problem ist, dass die Queryable-Versionen Überspringen und annehmen einfache integer-Parameter und nicht die lambda-Ausdrücke, also während LINQ to Entities können Sie sehen, die Werte, die Sie übergeben, es kann nicht sehen, die Tatsache, dass Sie verwendet eine variable zu übergeben (in anderen Worten, Methoden, wie das Überspringen und Nehmen Sie don T haben Zugang zu dem Verfahren der Schließung).
Dies betrifft nicht nur die Parametrierung in LINQ to Entities, sondern auch die erlernte Erwartung, dass, wenn Sie übergeben Sie eine variable, um eine LINQ-Abfrage der aktuelle Wert der variable verwendet wird, jedes mal, wenn Sie re-führen Sie die Abfrage. E. g., so etwas wie dies funktioniert, Wo aber nicht Überspringen, oder Nehmen Sie:
Beachten Sie, dass diese Besonderheit wirkt sich auch auf ElementAt aber dieser ist derzeit nicht unterstützt, die von LINQ to Entities.
Hier ist ein trick, den Sie verwenden können, um die Kraft der Parametrisierung von Überspringen und Nehmen, und zur gleichen Zeit, machen Sie sich mehr wie andere query-Operatoren:
Der obigen Klasse definiert neue überlastungen Überspringen und Nehmen, die erwarten, dass ein lambda-Ausdruck, und kann daher-capture-Variablen. Mit den Methoden, wie dieses Ergebnis in der Variablen übersetzt Parameter, die von LINQ to Entities:
Hoffe, das hilft.
Methoden
Skip
undTop
vonObjectQuery<T>
parametrisiert werden kann. Es gibt ein Beispiel, bei MSDN.Ich habe eine ähnliche Sache in einem Modell meiner eigenen-und der sql server profiler zeigte die Teile
und
So, ja. Es kann getan werden. Und ich Stimme mit anderen, dass dies eine wertvolle Beobachtung, die Sie gemacht hier.
Top
- Methode anstelle der WiederverwendungTake
. Ich bin skipping/Teilnahme an einer anonymen Projektion also die Abfrage ist nicht der TypObjectQuery<T>
also ich bin mir nicht sicher, ob ich diesen Ansatz verwenden. Aber das gibt mir etwas zu untersuchen.Where()
, wenn explizit umgewandelt werden, um eine ObjectQuery (Abfrage-generator-Methoden werden nicht unterstützt LINQ to Entities-Abfragen. Für mehr Informationen, siehe Entity Framework-Dokumentation.)