Entity Framework 始终似乎在生成的 SQL 中使用 Skip()
和 Take()
提供的值的常量。
在下面这个极简化的示例中:
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();
上面的代码生成以下SQL查询: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
导致在 SQL 过程缓存中添加了 2 个 Adhoc 计划,每个计划使用了 1 次。
我的目标是将 Skip()
和 Take()
逻辑参数化,以生成以下 SQL 查询:
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
这将导致1个预编译计划添加到SQL过程缓存中,并使用2次。我有一些相当复杂的查询,第一次运行时会在SQL Server端产生显着的开销,而后续运行则会更快(因为它可以使用计划缓存)。请注意,这些更高级的查询已经使用sp_executesql,因为其他值是参数化的,所以我不担心这方面的问题。
以上生成的第一组查询基本上意味着任何分页逻辑都会为每个页面创建一个新的计划缓存条目,导致缓存膨胀并需要为每个页面承担计划生成开销。
我可以强制Entity Framework参数化值吗?对于其他的值,例如在“Where”子句中,有时它会参数化值,有时它会使用常量。
我完全错了吗?Entity Framework现有的行为是否比我期望的行为更好?
编辑:如有关联,请注意我正在使用Entity Framework 4.2。
编辑2:这个问题不是Entity Framework/Linq to SQL: Skip & Take的重复,它只是询问如何确保
Skip
和Take
在SQL中执行而不是在客户端上执行。这个问题涉及参数化这些值。