SQL Server 2008 R2
请注意,我了解性能问题可能会变得复杂。我的问题更为笼统,并且与ISNULL
构造的行为有关。
我有一个SQL查询需要根据给定的参数进行筛选,我通过在查询中附加以下子句来实现:
WHERE tbl.Col1 = ISNULL(@col1, tbl.Col1)
我看到的是我的查询在SSMS中执行得很好,但是当它被送到dapper时会超时。
如果我用下面的行为等效表达式替换过滤器:
WHERE @col1 IS NULL OR tbl.Col1 = @col1
查询执行时没有超时。
问题:为什么?在此方案中使用时ISNULL
是否存在已知问题会降低查询执行速度?
(我还没有尝试过分析查询,但接下来会这样做)
答案 0 :(得分:1)
WHERE子句中的函数阻止SQL在字段上使用索引。因此,如果Col1在Col1上具有非聚集索引,则可以在第二个示例中使用它,但不能在第一个示例中使用。这将导致函数评估每一行(聚集索引扫描),这可能是主要的性能损失。
有关详细信息和示例,请参阅文章:
答案 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):
注意:如果@col1
和tbl.Col1
具有不同的数据类型,则SQL Server会将tbl.Col1
值转换为@col1
的数据类型。这种隐式转换可以阻止Seek
上的tbl.Col1
(当@col1
不为空时)。
2)WHERE @col1 IS NULL OR tbl.Col1 = @col1
是SARG-able predicates,这意味着SQL Server可以使用Seek
过滤行(如果tbl.Col1
上有索引)。