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
В результате 2 плана Adhoc добавляются в кэш процедур SQL с 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 с двумя вариантами использования.
У меня есть несколько довольно сложных запросов, и я испытываю значительные накладные расходы (на стороне SQL Server) при первом запуске и намного более быстрое выполнение при последующих запусках (поскольку он может использовать кэш плана). Обратите внимание, что эти более сложные запросы уже используют sp_executesql, поскольку другие значения параметризованы, поэтому я не беспокоюсь об этом аспекте.
Первый набор запросов, сгенерированный выше, в основном означает, что любая логика разбиения на страницы создаст новую запись в кэше плана для каждой страницы, раздувая кэш и требуя накладных расходов генерации плана для каждой страницы.
Могу ли я заставить Entity Framework параметризировать значения? Я заметил для других значений, например в предложениях Where
иногда параметризует значения, а иногда использует константы.
Я полностью вышел на обед? Есть ли какая-то причина, по которой существующее поведение Entity Framework лучше, чем желаемое?
Edit:
В случае, если это уместно, я должен упомянуть, что я использую Entity Framework 4.2.
Редактировать 2:
Этот вопрос не является дубликатом Entity Framework / Linq to SQL: Skip & Take , который просто спрашивает, как обеспечить выполнение Skip
и Take
в SQL, а не на клиенте. Этот вопрос относится к параметризации этих значений.