我对一个实体的简单分页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