Заставить Entity Framework использовать параметризацию SQL для лучшего повторного использования кэша процессов SQL

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 с одним использованием каждого.

Я бы хотел параметризовать логику 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. на клиенте. Этот вопрос относится к параметризации этих значений.

20
задан Community 23 May 2017 в 10:30
поделиться