Sql server 2005 存储过程日期参数筛选器-如果为Null,则忽略
我在存储过程中使用以下SQL来不按日期筛选空参数Sql server 2005 存储过程日期参数筛选器-如果为Null,则忽略,sql-server-2005,tsql,stored-procedures,Sql Server 2005,Tsql,Stored Procedures,我在存储过程中使用以下SQL来不按日期筛选空参数 WHERE (Allocated >= ISNULL(@allocatedStartDate, '01/01/1900') AND Allocated <= ISNULL(@allocatedEndDate,'01/01/3000')) AND (MatterOpened >= ISNULL(@matterOpenedStartDate, '01/01/1900') AND MatterOpened <
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不要检查查询中的变量是否为空,而是在存储过程开始时检查它们,并将值更改为默认值
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')
不要在查询中检查变量是否为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')
在很多情况下,动态SQL对您来说可能更好,而不是试图依赖优化器来缓存空参数和非空参数的良好计划
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。在很多情况下,动态SQL对您来说会更好,而不是试图依赖优化器来缓存空参数和非空参数的好计划
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。可能是这样的:
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)
也许是这样的:
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)
或者让查询优化器拥有它:
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 )
请注意,这在逻辑上并不等同于您的查询。最后一行使用列MatteRoped,而不是Allocated,因为我认为这是一个印刷错误
如果性能确实是一个问题,您可能需要考虑添加索引和更改存储过程来执行基于参数的不同查询。至少将其分为:无筛选器、仅在已分配时筛选、仅在MatteRoped时筛选、在两列上筛选。
或者让查询优化器拥有它: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 )
请注意,这在逻辑上并不等同于您的查询。最后一行使用列MatteRoped,而不是Allocated,因为我认为这是一个印刷错误
如果性能确实是一个问题,您可能需要考虑添加索引和更改存储过程来执行基于参数的不同查询。至少将其分为:无筛选器、仅在已分配时筛选器、仅在无约束时筛选器、,在两列上进行筛选。
您可能希望将MatteRopend而不是Allocated放在查询的最后一行中-对吗?您可能希望将MatteRopend而不是Allocated放在查询的最后一行中-对吗?还为了避免您可能希望通过创建单独的局部变量来测试的参数嗅探问题,将参数值传递给它们,并在查询中使用局部变量。反之亦然。当第一次编译基于非典型参数时,参数嗅探可能不好。此外,为了避免参数嗅探问题,您可能需要创建单独的局部变量,将参数值传递给它们,并在查询中使用局部变量进行测试。反之亦然。当第一次编译基于非典型参数时,参数嗅探可能很糟糕。我认为这是一个偏好问题,但基于参数的完全不同的查询可能意味着在进行更改时会有大量冗余代码和额外维护。我不喜欢动态SQL的《红海》,但如果你能清楚地读到这一点,我宁愿做一个改变,而不是四个或更多;我们不知道这些是唯一的参数…@AaronBertrand-同意。如果知道82%*的调用不执行过滤,那么在未过滤查询和完全过滤查询之间选择一个简单的If可能是有意义的。另一种可能性是使用WITH RECOMPILE根据参数优化每个查询。我们需要分析工作负载和环境,以做出明智的决策。巧合的是,82%的统计数据都是当场生成的。我想这是一个偏好问题,但基于参数的完全不同的查询可能意味着在进行更改时需要大量冗余代码和额外维护。我不喜欢动态SQL的《红海》,但如果你能清楚地读到这一点,我宁愿做一个改变,而不是四个或更多;我们不知道这些是唯一的参数…@AaronBertrand-同意。如果知道82%*的调用不执行过滤,那么在未过滤查询和完全过滤查询之间选择一个简单的If可能是有意义的。另一种可能性是使用WITH RECOMPILE根据参数优化每个查询。需要 分析工作量和环境,做出明智的决策。巧合的是,82%的统计数据是在现场完成的。