添加条件测试时缓慢存在检查

时间:2009-07-07 21:03:14

标签: sql-server-2005 tsql

我使用此条件作为where子句的一部分:exists (select * from PRPB PB where PA.mid = PB.mid and (@inpo is null or PB.inpo = @inpo)) order by price

在测试非null的@inpo值时,我注意到当我改为使用这个条件时,查询运行得更快:exists (select * from PRPB PB where PA.mid = PB.mid and (PB.inpo = @inpo)) order by price。这导致一个不可忽略的速度差异表明我将被迫使用if语句的两个单独的查询,以决定是否过滤掉@inpo。这对我来说是件坏事,因为它意味着很多代码重复。

我尝试过的事情:

  • 创建一个存储@inpo是否为非null并与之比较的位。
  • 将无效检查移到存在语句的左侧并执行或完成整个事情(这会让事情变得很慢,这让我感到惊讶)。
  • 将无效检查移动到where类的最左边,并使用所有子句进行定位(这也会减慢很多事情,这根本不会让我感到惊讶,因为这意味着无效检查总是会发生,无论是否PA.mid = PB.mid)。

我的目标是让它在没有我的查询的两个副本的情况下更快地执行此检查。

这可能吗?如果没有,为什么不呢?如果是这样,怎么样?

注意:另请参阅第二个相关问题here

2 个答案:

答案 0 :(得分:1)

要在不牺牲性能损失的情况下重用代码,您可以创建视图或创建内联UDF。两者都是由优化器扩展的宏。例如,而不是以下代码重复:

CREATE PROCEDURE MyProc
  @i1 INT,
  @inpo INT
AS
BEGIN
IF @inpo IS NULL BEGIN
  SELECT a,b,c 
    FROM dbo.YourTable 
    WHERE i1 = @i1 
    ORDER BY c;
END ELSE BEGIN
  SELECT a,b,c 
    FROM dbo.YourTable 
    WHERE i1 = @i1 
      AND inpo = @inpo
    ORDER BY c;
END
END

将查询包装在内联udf中并重用它:

CREATE FUNCTION dbo.ReuseMyQuery(@i1 INT)
RETURNS TABLE AS RETURN(
SELECT a,b,c, inpo FROM dbo.YourTable WHERE i1 = @i1
)
GO

ALTER PROCEDURE MyProc
  @i1 INT,
  @inpo INT
AS
BEGIN
IF @inpo IS NULL BEGIN
  SELECT a,b,c 
    FROM dbo.ReuseMyQuery(@i1)
    ORDER BY c;
END ELSE BEGIN
  SELECT a,b,c 
    FROM dbo.ReuseMyQuery(@i1)
    WHERE inpo = @inpo
    ORDER BY c;
END
END

答案 1 :(得分:0)

如果您尝试这样做会怎样:

exists (select * from PRPB PB where PA.mid = PB.mid and PB.inpo = ISNULL(@inpo, PB.inpo)) order by price

当@inpo为NULL时,ISNULL函数将使它返回第二个参数,并返回PB.inpo,然后该等式将始终评估为true,这与您的条件匹配。