使用ISNULL处理可选参数会损害性能

时间:2014-07-02 20:10:51

标签: sql-server sql-server-2008-r2 ssms isnull sqlperformance

SQL Server 2008 R2

请注意,我了解性能问题可能会变得复杂。我的问题更为笼统,并且与ISNULL构造的行为有关。

我有一个SQL查询需要根据给定的参数进行筛选,我通过在查询中附加以下子句来实现:

WHERE tbl.Col1 = ISNULL(@col1, tbl.Col1)

我看到的是我的查询在SSMS中执行得很好,但是当它被送到dapper时会超时。

如果我用下面的行为等效表达式替换过滤器:

WHERE @col1 IS NULL OR tbl.Col1 = @col1

查询执行时没有超时。

问题:为什么?在此方案中使用时ISNULL是否存在已知问题会降低查询执行速度?

(我还没有尝试过分析查询,但接下来会这样做)

2 个答案:

答案 0 :(得分:1)

WHERE子句中的函数阻止SQL在字段上使用索引。因此,如果Col1在Col1上具有非聚集索引,则可以在第二个示例中使用它,但不能在第一个示例中使用。这将导致函数评估每一行(聚集索引扫描),这可能是主要的性能损失。

有关详细信息和示例,请参阅文章:

Database Journal

MSSQLTips

答案 1 :(得分:1)

注意:这个问题与ISNULL(@col1, tbl.Col1)有关,而不是ISNULL(tbl.Col1, @col1)

WHERE tbl.Col1 = ISNULL(@col1, tbl.Col1)

1)您可以添加RECOMPILE查询提示。在这种情况下,SQL Server将在每次执行时[重新]编译此查询。这意味着每次执行时都会重新评估谓词tbl.Col1 = ISNULL(@col1, tbl.Col1)

  • 如果@col包含NULL,那么它会删除条件,因为该列是强制性的(NOT NULL;因为WHERE tbl.Col1 = ISNULL(@col1, tbl.Col1) => WHERE tbl.Col1 = tbl.Col1 ),否则

  • 如果@col包含某些内容(不为空),则WHERE tbl.Col1 = ISNULL(@col1, tbl.Col1)会转换为WHERE tbl.Col1 = @col1

示例(Adventure Works for SQL Server 2012):

enter image description here

注意:如果@col1tbl.Col1具有不同的数据类型,则SQL Server会将tbl.Col1值转换为@col1的数据类型。这种隐式转换可以阻止Seek上的tbl.Col1(当@col1不为空时)。

2)WHERE @col1 IS NULL OR tbl.Col1 = @col1SARG-able predicates,这意味着SQL Server可以使用Seek过滤行(如果tbl.Col1上有索引)。

另见Conor vs. more SARGable predicates