【问题标题】:Optimize multiple joins with table functions使用表函数优化多个连接
【发布时间】:2009-09-29 13:30:18
【问题描述】:

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

我怎样才能避免表变量并且仍然有一个快速的查询?

例如,我们有一个类似的 SQL 查询

选择 P.ProjectName、A.Number、B.Number 来自项目 AS P 左加入 dbo.fn_ProjectNumber(@dateA) 作为 A ON P.ProjectID = A.ProjectID 左连接 dbo.fn_ProjectNumber(@dateB) AS B ON P.ProjectID = B.ProjectID

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

插入@tempA 选择 P.ProjectID、A.Number 来自项目 AS P 左加入 dbo.fn_ProjectNumber(@dateA) 作为 A ON P.ProjectID = A.ProjectID 插入@tempB 选择 P.ProjectID、B.Number 来自项目 AS P 左连接 dbo.fn_ProjectNumber(@dateB) AS B ON P.ProjectID = B.ProjectID 选择 P.ProjectName、A.Number、B.Number 来自项目 AS P 左加入 @tempA 作为 A ON P.ProjectID = A.ProjectID 左加入 @tempA 作为 B ON P.ProjectID = B.ProjectID

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


更多细节:

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

【问题讨论】:

  • 您没有提供太多信息。如何显示函数中的代码、执行计划(SET SHOWPLAN_ALL ON)等...

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


【解决方案1】:

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

原文:

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

已修复:

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 --<<<<<

【讨论】:

  • 啊,在我的示例中这是一个错误。在实际情况下,别名是正确的......
【解决方案2】:

您有什么特别的原因要避免使用表变量吗?它们可以是一种很好的优化技术,并且不会留下任何临时对象需要清理。

无论如何,如果你不想那样做,你可以随时尝试

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

【讨论】:

    【解决方案3】:

    连接速度很慢,因为在您的示例查询中,您为表 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>
    

    【讨论】:

    • 是什么让您认为该函数是为每一行调用的?代码:LEFT JOIN dbo.fn_ProjectNumber(@dateA) AS A ON P.ProjectID = A.ProjectID 对我来说似乎只被调用一次。
    • 嗯,没错。我基于这样的语句,即查询运行速度比填充临时表时慢得多,因为这通常是正在发生的事情——但你是对的,它们不应该经常被调用。慢多少?查看查询计划会很有用。
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2011-01-06
      • 2023-03-12
      • 2016-12-10
      • 2019-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多