存储过程日期参数过滤器 - 如果为空则忽略

时间:2012-02-09 15:51:13

标签: sql-server-2005 tsql stored-procedures

我在我的存储过程中使用以下SQL,如果它们为null,则不按日期参数进行过滤。

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 个答案:

答案 0 :(得分:3)

或者让查询优化器拥有它:

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,因为我认为这是一个印刷错误。

如果性能确实存在问题,您可能需要考虑添加索引并更改存储过程以根据参数执行不同的查询。至少将其分解为:无过滤器,仅在分配时过滤,仅在MatterOpened上过滤,在两列上过滤。

答案 1 :(得分:1)

在很多情况下,动态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;

不,维护起来并不好玩,但每个变体应该在缓存中得到自己的计划。您将要使用不同的设置进行测试,以便针对临时工作负载进行优化和#34;和数据库级别的参数化设置。哎呀,刚刚注意到了2005年。为了未来(以及任何2005年仍然没有坚持的读者),请记住这些。

另请务必使用EXEC sp_executesql而不是EXEC

答案 2 :(得分:0)

不是检查查询中的变量是否为null,而是在存储过程的开头检查它们并将值更改为默认值

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')

答案 3 :(得分:0)

也许是这样的:

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)