ich eine einfache ausgelagertem Linq-Abfrage gegen eine Einheit haben:Entity Framework erzeugt ineffiziente SQL für ausgelagerte Abfrage
var data = (from t in ctx.ObjectContext.Widgets
where t.CampaignId == campaignId &&
t.CalendarEventId == calendarEventId
(t.RecurringEventId IS NULL OR t.RecurringEventId = recurringEventId)
select t);
data = data.OrderBy(t => t.Id);
if (page > 0)
{
data = data.Skip(rows * (page - 1)).Take(rows);
}
var l = data.ToList();
ich es erwartet SQL ähnlich wie generieren:
select top 50 * from Widgets w where CampaignId = xxx AND CalendarEventId = yyy AND (RecurringEventId IS NULL OR RecurringEventId = zzz) order by w.Id
Wenn ich die oben laufen Abfrage in SSMS, es schnell zurück (musste meine Indizes zuerst neu erstellen).
Das generierte SQL ist jedoch unterschiedlich. Es enthält eine verschachtelte Abfrage, wie unten dargestellt:
SELECT TOP (50)
[Project1].[Id] AS [Id],
[Project1].[CampaignId] AS [CampaignId]
<redacted>
FROM (SELECT [Project1].[Id] AS [Id],
[Project1].[CampaignId] AS [CampaignId],
<redacted>,
row_number() OVER (ORDER BY [Project1].[Id] ASC) AS [row_number]
FROM (SELECT
[Extent1].[Id] AS [Id],
[Extent1].[CampaignId] AS [CampaignId],
<redacted>
FROM [dbo].[Widgets] AS [Extent1]
WHERE ([Extent1].[CampaignId] = @p__linq__0) AND ([Extent1].[CalendarEventId] = @p__linq__1) AND ([Extent1].[RecurringEventId] = @p__linq__2 OR [Extent1].[RecurringEventId] IS NULL)
) AS [Project1]
) AS [Project1]
WHERE [Project1].[row_number] > 0
ORDER BY [Project1].[Id] ASC
Die Widgets Tabelle ist enorm und die innere Abfrage gibt 100000s von Datensätzen, ein Timeout verursacht.
Kann ich irgendetwas tun, um die Generation zu ändern? Was mache ich falsch? die Ergebnisse zurück relativ schnell
UPDATE
ich es endlich geschafft, meinen Code zu Refactoring:
var data = (from t in ctx.ObjectContext.Widgets
where t.CampaignId == campaignId &&
t.CalendarEventId == calendarEventId
(t.RecurringEventId IS NULL OR t.RecurringEventId = recurringEventId)
select t)).AsEnumerable().Select((item, index) => new { Index = index, Item = item });
data = data.OrderBy(t => t.Index);
if (page > 0)
{
data = data.Where(t => t.Index >= (rows * (page - 1)));
}
data = data.Take(rows);
Hinweis, die page > 0
Logik ist einfach verwendet einen ungültigen Parameter zu verhindern, verwendet werden; es macht keine Optimierung. In der Tat, page > 1
, während gültig, bietet keine spürbare Optimierung für die erste Seite; seit dem Where
ist kein langsamer Vorgang.
können Sie die Abfrage zeigen planen? Ich verstehe nicht, warum die innere Abfrage hier vollständig abgerufen werden würde. Es ist etwas falsch mit der Art, wie SQL ausgeführt wird. –
Wie schnell ist es, wenn Sie Ihrer Abfrage den Befehl 'order by' hinzufügen? zB 'wähle Top 50 * aus Widgets, wobei CampaignId = xxx AND CalendarEventId = yyy order by id' – Aducci
Dein schnelles SQL hat keine ORDER BY. Was passiert, wenn Sie das hinzufügen? – hvd