Фильтры параметров даты хранимой процедуры - Игнорировать, если Null - PullRequest
1 голос
/ 09 февраля 2012

Я использую следующий SQL в своей хранимой процедуре, чтобы не фильтровать параметры даты, если они равны нулю.

WHERE (Allocated >= ISNULL(@allocatedStartDate, '01/01/1900') 
       AND Allocated <= ISNULL(@allocatedEndDate,'01/01/3000'))
AND
(MatterOpened >= ISNULL(@matterOpenedStartDate, '01/01/1900') 
 AND MatterOpened <= ISNULL(@matterOpenedEndDate, '01/01/3000'))

Даст ли это какой-нибудь удар по производительности при работе с большим количеством записей?

Есть ли лучший способ сделать это?

Количество записей - около 500k

Ответы [ 4 ]

3 голосов
/ 09 февраля 2012

Или просто позвольте оптимизатору запросов иметь его:

WHERE ( @allocatedStartDate is NULL or Allocated >= allocatedStartDate ) and
   ( @allocatedEndDate is NULL or Allocated <= @allocatedEndDate ) and
   ( @matterOpenedStartDate is NULL or MatterOpened >= @matterOpenedStartDate ) and
   ( @matterOpenedEndDate is NULL or MatterOpened <= @matterOpenedEndDate )

Обратите внимание, что это логически не эквивалентно вашему запросу. В последней строке используется столбец MatterOpened, а не Allocated, как я полагаю, это типографская ошибка.

Если производительность действительно является проблемой, вы можете рассмотреть возможность добавления индексов и изменения хранимой процедуры для выполнения различных запросов на основе параметров. По крайней мере, разбейте его на: без фильтра, фильтр только для Allocated, фильтр только для MatterOpened, фильтр для обоих столбцов.

1 голос
/ 09 февраля 2012

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

DECLARE @sql NVARCHAR(MAX);

SET @sql = N'SELECT 
... 
WHERE 1 = 1';

SET @sql = @sql + CASE WHEN @allocatedStartDate IS NOT NULL THEN 
    ' AND Allocated >= ''' + CONVERT(CHAR(8), @allocatedStartDate, 112) + '''';

-- repeat for other clauses

EXEC sp_executesql @sql;

Нет, поддерживать не интересно, но каждый вариант должен иметь свой собственный план в кеше. Вы захотите провести тестирование с различными настройками «Оптимизация для специальных рабочих нагрузок» и параметрами параметризации на уровне базы данных. Ой, только что заметил 2005 год. Помните об этом на будущее (и любых читателей, которые еще не застряли в 2005 году).

Также обязательно используйте EXEC sp_executesql, а не EXEC.

0 голосов
/ 09 февраля 2012

Может быть, что-то вроде этого:

DECLARE @allocatedStartDate DATETIME=GETDATE()
DECLARE @allocatedEndDate DATETIME=GETDATE()-2

;WITH CTE AS
(
    SELECT 
        ISNULL(@allocatedStartDate, '01/01/1900') AS allocatedStartDate,
        ISNULL(@allocatedEndDate,'01/01/3000') AS allocatedEndDate 
)
SELECT
    *
FROM
    YourTable
    CROSS JOIN CTE
WHERE (Allocated >= CTE.allocatedStartDate 
       AND Allocated <= CTE.allocatedEndDate)
AND
(MatterOpened >= CTE.allocatedStartDate 
 AND Allocated <= CTE.allocatedEndDate)
0 голосов
/ 09 февраля 2012

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

SELECT
   @allocatedStartDate = ISNULL(@allocatedStartDate, '01/01/1900'),
   @allocatedEndDate = ISNULL(@allocatedEndDate,'01/01/3000'),
   @matterOpenedStartDate = ISNULL(@matterOpenedStartDate, '01/01/1900'),
   @matterOpenedEndDate = ISNULL(@matterOpenedEndDate, '01/01/3000')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...