有没有办法对WHERE子句中的变量进行空检查仅发生一次?


12

我对一个看起来像这样的大表进行查询:

declare @myIdParam int = 1

select * 
from myTable
where (@myIdParam is null or myTable.Id = @myIdParam)

在where子句中有几个类似的条件,并且也有很多联接,但这是一个摘要。

实际上,如果@myIdParam为null,则我们不想使用此参数来限制结果。

我不是数据库专家,但是从我的测试看来,此NULL检查是针对每条记录执行的,并且没有以任何方式进行优化。

如果我删除了空检查并假定参数不为空,则查询将立即返回。否则,最多需要十秒钟。

有没有一种方法可以对此进行优化,以便在运行时仅进行一次检查?


1
看看这个答案:stackoverflow.com/questions/3415582/…tl ; dr使用OPTION(RECOMPILE)
vercelli

@vercelli这可以解决问题。考虑到这个问题实际上是关于可选参数的,我想说它是您链接的那个的重复。
Mystagogue

可能是这样,但这是6年前的帖子。也许在SqlServer 2014或2016中有一种新方法。(我在2014年对其进行了测试,没有进行重新编译,并且花了很
长时间

由于您的实际查询具有许多可选参数,因此动态SQL将提供最佳性能。有关该主题的完整文章,请参见sommarskog.se/dyn-search.html
丹·古兹曼

@DanGuzman使用问题Vercelli链接中概述的WITH RECOMPILE可以将查询时间从不到一分钟缩短为几乎即时且具有高度选择性的条件。我认为这是平衡性能和可读性的最佳选择。
Mystagogue

Answers:


8

一种方法是使用动态SQL,使用空检查来有选择地添加where子句的该部分。

declare @myIdParam int = 1
declare @vc_dynamicsql varchar(max)

set @vc_dynamicsql = 'select * from myTable where 1=1'

if @myIdParam is not null
    set @vc_dynamicsql = @vc_dynamicsql + ' and  myTable.Id = @myIdParam'

EXECUTE sp_executesql @vc_dynamicsql

2
我真的不希望这样做,但这是一个解决方案。我希望有人能提供更好的服务。
Mystagogue

1
这是处理此类搜索查询的最佳方法。@vercelli引用的stackoverflow答案包含有关如何执行此操作的出色参考。
Max Vernon

这是最好的方法,但我确实注意到sp_ExecuteSQL缺少@params参数,并且该@vc_dynamicsql参数必须为NVARCHAR
James Anderson

4

例如,每当您将函数放在“ ISNULL(@var,table.col)”列周围时,都会删除SQL使用索引的功能。如果您想将其保留在单个查询中,这实际上是最佳性能的选择。

@var IS NULL or @var = table.col

否则,您有两个选择。第一个是动态SQL,@ Mystagogue的答案足以满足要求,否则您可以输入两个查询,如下所示:

IF @var is NULL
     SELECT * FROM table
ELSE
     SELECT * FROM table WHERE @var = col

在这种格式和动态SQL中,您实际上将为每个查询获得不同的查询计划(这可能会产生更好的性能)。


问题中的Sql没有使用ISNULL或任何其他函数。
Mystagogue,2016年

我正在引用一个已删除的答案。
肯尼斯·费舍尔

0

好吧,您可以:

declare @myIdParam int = 1;

select *
from myTable
where nullif(@myIdParam, myTable.Id) is null;

但是请记住,该nullif()函数本质上是包装case。这不是灵丹妙药消除OR并加快查询速度的灵丹妙药。


在where子句中使用函数会对性能产生负面影响,因为它阻止使用索引(或者我听说过)
Mystagogue

@Mystagogue,是的-它通常使搜索条件不可识别。las,这是我知道如何不借助动态SQL或Multiple UNIONS 来回答问题的唯一方法。完成这项确切的任务后,我选择了动态SQL。
罗杰·沃尔夫,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.