2009-07-07 51 views
0

我正在使用此条件作为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商店是否非空,并与比较。
  • 将无效性检查移到exists语句的左边,并对整个事物做一个或整个事情(这会让事情减慢很多,这让我很惊讶)。
  • 将无效性检查移动到where类的最左边,并用所有子句进行排序(这也会减慢很多事情的发生,这根本不会让我感到意外,因为它意味着无论检查总是发生,无论不管是否PA.mid = PB.mid)。

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

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

备注:另请参阅第2个相关问题here

+0

@Alex:回滚。没有人使用sqlserver2005标签,因此除了相当流行的sqlserver2005标签之外,使用它看起来很愚蠢。 sql标签是多余的,但不那么愚蠢。 – Brian 2009-07-07 21:55:09

+0

幕后发生了一些事情。昨天标签sqlserver2005很流行,现在显然它的所有内容都被重新标记为sql-server-2005。 – 2009-07-08 00:41:42

+0

你试过了(PB.inpo = @inpo还是@inpo为空)? – 2009-07-08 09:30:04

回答

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 
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,与您的或条件匹配。