SQL Server - 比较NULL非常慢

时间:2014-11-28 18:31:22

标签: sql asp.net sql-server performance

我想加快以下查询

WHERE子句中有两个条件(参见下面的查询以供参考)

目前,大约需要60秒。但是,如果我删除where子句中的第一个条件(@Query为NULL),那么它几乎立即返回。

有关如何加快速度的想法吗?表中约有700k行,这只会增长。

(注意:下面显示的查询被剥离为它的本质,我严格使用硬编码值来简化查询,以便将焦点拉向上面概述的部分)

declare @Query nvarchar(255)
select @Query = 'oceans'

select
    * 
from

(select 
  row_number() over( order by b.BookTitle) as RowNumber, 
  b.*
from
  Books b (nolock)
where
 -- If I remove this first condition "@Query is NULL", then it returns almost immediately
 -- Otherwise if I keep this here, it takes around 1 minute
 -- Yes, I have full-text index on BookTitle, as well as a regular index.
  (@Query is NULL) or (contains(b.BookTitle, @Query))
) as t1

where t1.RowNumber between 40 and 60

4 个答案:

答案 0 :(得分:5)

你能把它分成两个查询吗? or经常会导致优化问题:

if @Query is null
begin
    select * 
    from (select row_number() over( order by b.BookTitle) as RowNumber, b.*
          from Books b (nolock)
          where @Query is NULL
         ) as t1
    where t1.RowNumber between 40 and 60;
end
else
begin
    select * 
    from (select row_number() over( order by b.BookTitle) as RowNumber, b.*
          from Books b (nolock)
          where contains(b.BookTitle, @Query)
         ) as t1
    where t1.RowNumber between 40 and 60;
end

答案 1 :(得分:2)

如果@query是存储过程的参数,则延迟可能归因于Parameter sniffing:

  

编译或重新编译存储过程时,参数   为该调用传递的值是"嗅探"并用于   基数估计。实际效果是计划得到优化   好像那些特定的参数值被用作文字中的文字   查询。

在这种情况下使用的解决方法是在存储过程中声明一个虚拟局部变量,并为该变量分配被嗅探的参数的内容,例如

CREATE PROCEDURE [dbo].[usp_MySproc](@Query nvarchar(255)
AS
BEGIN

    -- Declare dummy variable   
    DECLARE @localQuery nvarchar(255)

    -- Disable parameter sniffing       
    SET @localQuery = @Query

    -- etc ...
END

答案 2 :(得分:1)

你有没有比较执行计划(@Query是否为NULL)?

我只会将此过程用于搜索特定的书名并删除(@Query为NULL)。如果您想要行号范围内的所有书名,您也可以使用视图。 当您执行存储过程并且缓存中没有执行计划时,SQL Server将生成一个存储过程。也许第一个调用者使用@Query ='ocean'。参数值的每个其他调用都将使用相同的计划。当您使用@Query = NULL调用proc时,SQL Server必须读取700.000行。但执行计划和内存授权基于对“海洋”的查询。因此,它会溢出到tempDb,因为没有足够的内存,执行计划中使用的运算符可能不是最佳的。

答案 3 :(得分:0)

这是一个可以使用coalesce来加快速度的选项:

...
where contains(b.BookTitle, coalesce(@Query,b.BookTitle))
...