Как DateTime.Now влияет на кэширование плана запросов в SQL Server? - PullRequest
2 голосов
/ 05 мая 2010

Вопрос:

Предотвращает ли передача DateTime.Now в качестве параметра для процесса SQL Server от кэширования плана запроса? Если да, то веб-приложение упускает огромный прирост производительности?

Возможное решение:

Я думал, что DateTime.Today.AddDays(1) будет возможным решением. Он будет передавать ту же дату окончания в sql proc (в день). И пользователь все равно получит последние данные. Пожалуйста, говорите и с этим.

Пример:

Допустим, у нас есть хранимая процедура. Он сообщает данные обратно пользователю на веб-странице. Пользователь может установить диапазон дат. Если пользователь устанавливает текущую дату как «конечную дату», которая включает сегодняшние данные, веб-приложение передает DateTime.Now в sql proc.

Допустим, один пользователь запускает отчет - от 5/1/2010 до now - многократно. На веб-странице пользователь видит 5/1/2010 до 5/4/2010. Но веб-приложение передает DateTime.Now в sql proc в качестве даты окончания. Таким образом, конечная дата в процедуре всегда будет отличаться, хотя пользователь запрашивает аналогичный диапазон дат.

Предположим, что количество записей в таблице и количество пользователей велико. Так что любой выигрыш в производительности имеет значение. Отсюда важность вопроса.

Пример процедуры и выполнения (если это помогает понять):

CREATE PROCEDURE GetFooData
    @StartDate datetime
    @EndDate datetime
AS

    SELECT *
    FROM Foo
    WHERE LogDate >= @StartDate
    AND LogDate < @EndDate

Вот пример выполнения с использованием DateTime.Now:

.
EXEC GetFooData '2010-05-01', '2010-05-04 15:41:27' -- passed in DateTime.Now

Вот пример выполнения с использованием DateTime.Today.AddDays (1)

EXEC GetFooData '2010-05-01', '2010-05-05' -- passed in DateTime.Today.AddDays(1)

Для обоих процедур возвращаются одинаковые данные, поскольку текущее время: 2010-05-04 15:41:27.

Ответы [ 3 ]

6 голосов
/ 05 мая 2010

План запроса будет кэшироваться независимо от значений параметров. Параметры в основном гарантируют , что существует непротиворечивый, многократно используемый запрос, так как он является безопасным с точки зрения типов для SQL-сервера.

Вам нужен не план запроса, а кеширование результатов. И это будет зависеть от поведения, которое вы описываете.

Так как кажется, что вы обрабатываете только целые дни, вы можете попробовать ввести даты, а не даты и время, чтобы минимизировать различные значения параметров. Также попробуйте кэшировать результаты запросов в приложении вместо того, чтобы каждый раз выполнять обход базы данных.

1 голос
/ 05 мая 2010

В вашем случае, вы, вероятно, в порядке, если второй параметр в реальном времени просто смещается вверх.

Однако возможно стать жертвой перехвата параметров , когда первое выполнение (которое создает кэшированный план выполнения) вызывается с параметрами, которые создают план, который обычно не подходит для других параметров. обычно используется (или профиль данных резко меняется). Более поздние вызовы могут использовать план, который иногда настолько плох, что он даже не будет выполнен должным образом.

Если ваш профиль данных резко меняется из-за различных вариантов параметров, и план выполнения становится плохим для определенных вариантов параметров, вы можете маскировать параметры в локальные переменные - это эффективно предотвратит прослушивание параметров в SQL Server 2005. Существует также WITH RECOMPILE (либо в SP, либо в EXEC - но для SP с интенсивным вызовом, это нереальный вариант). В SQL Server 2008 я почти всегда использовал бы OPTIMIZE FOR UNKNOWN, что позволит избежать создания плана, основанного на прослушивании параметров. .

1 голос
/ 05 мая 2010

Поскольку вы вызываете хранимую процедуру, а не непосредственно запрос, то ваш единственный запрос, который изменяется, - это фактический пакет, отправляемый в SQL, EXEC GetFooData '2010-05-01', '2010-05-05' против GetFooData '2010-05-01', '2010-05-04 15:41:27'. Это тривиальная партия, которая будет генерировать тривиальный план. Хотя верно и то, что с технической точки зрения вы теряете некоторую производительность, это будет практически неизмеримо. Подробности этого успеха объясняются в этом ответе: Динамически создаваемый SQL и параметры в SQL Server

Хорошей новостью является то, что незначительные изменения в коде вызова SqlClient позволят вам даже упомянуть упомянутое там небольшое улучшение производительности. Измените код SqlCommand на явный вызов хранимой процедуры:

SqlCommand cmd = new SqlCommand("GetFooData", connection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@StartDate", dateFrom);
cmd.Parameters.AddWithValue("@EndDate", DateTime.Now);

В качестве примечания, хранение локализованного времени в базе данных не очень хорошая идея, поскольку клиенты находятся в разных часовых поясах, чем сервер, и из-за сложностей перехода на летнее время ночью. Гораздо лучшим решением будет всегда хранить время UTC и просто отформатировать его в приложении по местному времени пользователя.

...