2011-05-18 106 views
5

我有一个存储过程,需要一秒钟才能正常运行。用户需要来自该查询中另一个表的数据,因此我将这些数据与UNION ALL以及新表中缺少的一些虚拟列合并。SQL 2000 UNION ALL遗失查询优化

它在测试中工作正常,但是当我们将它部署到SQL 2000 Server时,它开始超时。旧的查询在一秒之内运行,两个新的查询都在一秒之内运行,但是当它们使用UNION ALL组合时,查询超时。

下面是查询外观的一般概念。真正的查询有大约20个输入参数和返回大约30或40列,但是这应该了解基本的概念:

CREATE PROCEDURE dbo.SearchHistory 
(
    @Criteria1 bigint, 
    @Criteria2 int, 
    @Criteria3 varchar(10) 
) 
AS 
BEGIN 
    -- Part 1 
    SELECT 
     A, 
     NULL AS B, 
     0 AS C, 
     D 
    FROM TableA 
    WHERE @Criteria1 IS NULL 
    AND @Criteria3 IS NULL 
    AND (A = @Criteria2 OR @Criteria2 IS NULL) 

UNION ALL 

    -- Part 2 
    SELECT 
     A, 
     NULL AS B, 
     0 AS C, 
     E 
    FROM TableA 
    WHERE @Criteria1 IS NULL 
    AND @Criteria3 IS NULL 
    AND (A = @Criteria2 OR @Criteria2 IS NULL) 

UNION ALL 

    -- Part 3 
    SELECT 
     A, 
     B, 
     C, 
     D 
    FROM TableB 
    WHERE (F = @Criteria1 OR @Criteria1 IS NULL) 
    AND (A = @Criteria2 OR @Criteria2 IS NULL) 
    AND (G = @Criteria3 OR @Criteria3 IS NULL) 
END 

在上面的例子中,@标准1不为空,所以第1和第2将返回0行,第3部分只返回3行。但如果我评论第一部分和第二部分,它会立即结束;如果我让他们进来,我会暂停。

你如何说服SQL Server在这种情况下不要搞乱它的执行计划?

+0

它给你'UNION ALL'的执行计划是什么?还有,如果你只是在3个单独的语句中插入一个'@ table_variable',并从最后选择一个呢? – 2011-05-18 22:23:17

+0

(我认为在选择列表中缺少所需逗号的语法错误;这是实际代码吗?) – 2011-05-18 22:26:28

+0

是否将该过程更改为CREATE PROCEDURE dbo.SearchHistory WITH RECOMPILE(...'help? – 2011-05-18 22:36:08

回答

3

我认为你的问题是由于SQL Server的参数嗅探。

http://elegantcode.com/2008/05/17/sql-parameter-sniffing-and-what-to-do-about-it/

http://blogs.msdn.com/b/queryoptteam/archive/2006/03/31/565991.aspx

我所遇到一个好几次。有几种方法。例如。像@Biff MaGriff建议的那样使用WITH RECOMPILE。我发现要解决的最简单的方法是将所有输入参数转换为本地参数,并使用本地参数。

+0

WITH RECOMPILE使所有的查询超时,而不仅仅是@ Criteria1是非NULL。我还没有到处尝试局部变量,太多的其他东西正在进行,但我仍然打算尝试它。 – 2011-05-24 19:51:55

0

如果没有看到执行计划,请不要回答(请将它们作为图像发布,每个部分一个,联合查询一个)。解决方法是使用临时表,在其中单独插入零件。然而,更好的解决方案是首先解决查询问题。