使用表函数优化多个连接

时间:2009-09-29 13:30:18

标签: sql-server join query-optimization table-variable

对于同一查询中的不同输入变量,我想多次使用相同的表函数连接。但是,在我的情况下,这比使用表变量和分别从表函数中选择要慢得多。

如何避免表变量并且仍然有快速查询?

例如,我们有一个像

这样的SQL查询
SELECT P.ProjectName, A.Number, B.Number
FROM Project AS P
LEFT JOIN dbo.fn_ProjectNumber(@dateA) AS A
    ON P.ProjectID = A.ProjectID
LEFT JOIN dbo.fn_ProjectNumber(@dateB) AS B
    ON P.ProjectID = B.ProjectID

但它比从函数中单独选择变量然后稍后加入要慢得多,例如:

INSERT INTO @tempA
SELECT P.ProjectID, A.Number
FROM Project AS P
LEFT JOIN dbo.fn_ProjectNumber(@dateA) AS A
    ON P.ProjectID = A.ProjectID

INSERT INTO @tempB
SELECT P.ProjectID, B.Number
FROM Project AS P
LEFT JOIN dbo.fn_ProjectNumber(@dateB) AS B
    ON P.ProjectID = B.ProjectID

SELECT P.ProjectName, A.Number, B.Number
FROM Project AS P
LEFT JOIN @tempA AS A
    ON P.ProjectID = A.ProjectID
LEFT JOIN @tempA AS B
    ON P.ProjectID = B.ProjectID

这可能是什么原因?有没有办法可以快速查询并避免表变量?


更多详情:

这只是一个类似于我正在做的例子,但函数fn_ProjectNumber(@date datetime)将包含四个表之间的连接...


    

4 个答案:

答案 0 :(得分:1)

尝试修复连接,在第二个LEFT JOIN中引用错误的别名:

ORIGINAL:

SELECT P.ProjectName, A.Number, B.Number
FROM Project AS P
LEFT JOIN dbo.fn_ProjectNumber(@dateA) AS A
    ON P.ProjectID = A.ProjectID
LEFT JOIN dbo.fn_ProjectNumber(@dateB) AS B
    ON P.ProjectID = A.ProjectID

FIXED:

SELECT P.ProjectName, A.Number, B.Number
FROM Project AS P
LEFT JOIN dbo.fn_ProjectNumber(@dateA) AS A
    ON P.ProjectID = A.ProjectID
LEFT JOIN dbo.fn_ProjectNumber(@dateB) AS B
    ON P.ProjectID = B.ProjectID --<<<<<

答案 1 :(得分:1)

您是否有任何特殊原因试图避免表变量?它们可以是一种很好的优化技术,不会留下任何临时对象进行清理。

无论如何,如果你不想这样做,你总是可以尝试

SELECT
    P.ProjectID, A.Number, B.Number
FROM
    Project AS P
        LEFT JOIN
            (SELECT P.ProjectID, A.Number
            FROM Project AS P
            LEFT JOIN dbo.fn_ProjectNumber(@dateA) AS A
               ON P.ProjectID = A.ProjectID
            ) AS A
                ON P.ProjectID = A.ProjectID
        LEFT JOIN
            (SELECT P.ProjectID, B.Number
            FROM Project AS P
            LEFT JOIN dbo.fn_ProjectNumber(@dateB) AS B
                ON P.ProjectID = B.ProjectID
            ) AS B
                ON P.ProjectID = B.ProjectID

答案 2 :(得分:1)

连接很慢,因为在您的示例查询中,您为表Project中的每一行调用一次函数。临时表的速度更快,因为你只调用一次函数。

避免临时表的一种方法是使用CTE(公共表表达式 - 它们不仅仅用于递归 - 在SQL 2005及更高版本中可用)。一般语法如下:

WITH cteTempName (<list of columns>)
 as (<your table function call>)
 SELECT <your query here, with "cteTempName" appearing as just another table to select from>

答案 3 :(得分:0)

可能连接速度较慢,因为您没有定义连接在一起的表之间的关系? 我对SQL Server中的查询性能了解不多,但定义关系将提高连接的性能。