我對一個實體的簡單分頁LINQ查詢:實體框架生成低效SQL對分頁查詢
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();
我預期產生類似SQL:
select top 50 * from Widgets w where CampaignId = xxx AND CalendarEventId = yyy AND (RecurringEventId IS NULL OR RecurringEventId = zzz) order by w.Id
當我運行上面在SSMS中查詢,它會很快返回(必須先重建我的索引)。
但是,生成的SQL是不同的。它包含一個嵌套查詢,如下所示:
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
小部件表是巨大的和內查詢返回的記錄100000s,引起超時。
有什麼我可以做的改變世代?我做錯了什麼?
UPDATE
我終於成功地重構我的代碼相對快速地返回結果:
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);
注意,page > 0
邏輯僅僅是用來防止使用無效的參數;它沒有優化。實際上,page > 1
雖然有效,但不會爲第1頁提供任何明顯的優化;因爲Where
不是一個緩慢的操作。
您能顯示查詢計劃?我不明白爲什麼內部查詢會在這裏完整檢索。 SQL執行的方式有問題。 –
將'order by'添加到查詢中時速度有多快?即'選擇頂部50 *的小部件,其中CampaignId = xxx和CalendarEventId = yyy按ID排序' – Aducci
您的快速SQL沒有ORDER BY。如果你添加了會發生什麼? – hvd