T-SQL ISNULL() 优化

6

我继承了一个存储过程,在其中有一个关联查询的语句:

WHERE a.is_active = 1
AND b.due_date <= ISNULL(@due_date_limit, b.due_date)

如何重写此代码以删除ISNULL函数,因为它导致严重的性能问题?

7个回答

7
在这种情况下,我会使用if语句来检查@due_date_limit变量。
IF (@due_date_limit IS NULL)
BEGIN
    ...
    WHERE   a.is_active = 1 --not required to compare b.due_date <= b.due_date
END
ELSE
BEGIN
    ...
    WHERE   a.is_active = 1
    AND     b.due_date <= @due_date_limit
END

3
AND @due_date_limit IS NULL OR b.due_date <= @due_date_limit

但我不确定它会更快。


索引并不是一项问题——即使有索引,它也只会在后半部分使用。这比ISNULL/COALESCE建议要好得多。 - OMG Ponies

3
这种类型查询性能不佳的最常见原因是优化器无法确定大多数查询的@due_date_limit典型值。通常,由后续执行重复使用的计划会偏向于该值为null的情况。
从SQL 2005开始,您可以使用“OPTIMIZE FOR”选项指导优化器:
WHERE a.is_active = 1
AND b.due_date <= ISNULL(@due_date_limit, b.due_date)
OPTION (OPTIMIZE FOR (@due_date_limit = '09/01/2009'))

如果参数为空,为什么还要比较值呢?你不需要这样做,因此不要在可选参数中使用ISNULL/COALESCE。 - OMG Ponies

2

due_Date上是否有索引?如果没有,请添加一个并检查性能。如果已经存在,则更改为两个单独的语句。

  If @due_date_limit is null
    Select [stuff]
    From Table
  Else
    Select [stuff]
    From Table  
    Where b.due_date <= @due_date_limit

但是要注意的是,未进行筛选(当@due_date_limit为空时),或使用“<=”进行筛选可能会返回大量记录,这将消除使用索引的任何机会,需要进行完整的表扫描。这可能是您所经历的情况。


1

@due_date_limit是一个存储过程变量,因此可以从这个查询中完全分离出来:

if (@due_date_limit is NULL) 
   <run query that works when @due_date_limit is NULL>
else 
   <run query that works when @due_date_limit is NOT NULL>

1
COALESCE(@due_date_limit, b.due_date)

可能有帮助


这将优雅地处理事情,但执行1 = 1等效操作是浪费。 - OMG Ponies

0

由于 @due_date_limit 是一个存储过程变量,您可以在查询之前检查它是否为 NULL,并在需要时将其设置为默认值,从而消除 WHERE 子句中的 ISNULL 检查。

IF (@due_date_limit IS NULL)
BEGIN
    SET @due_date_limit = '09/01/2009';
END

然后您的WHERE子句将简单地如下所示:

WHERE a.is_active = 1
AND b.due_date <= @due_date_limit

如果您需要与列记录相同以满足<=运算符条件,那么astander的答案是更好的解决方案,否则在查询之前像这样设置它,因为它会更快且没有检查。 - johntrepreneur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接