sql-server - 自连接中引用的SQL Server CTE速度很慢

标签 sql-server performance temp-tables common-table-expression

我编写了一个表值UDF,该值由CTE开始,以从大型表返回行的子集。
CTE中有多个联接。几个内部表和一个左表连接到其他表,这些表不包含很多行。
CTE具有where子句,该子句返回日期范围内的行,以便仅返回所需的行。

然后,我将在4个自左联接中引用此CTE,以便使用不同的标准来建立小计。

该查询非常复杂,但这是其简化的伪版本

WITH DataCTE as
(
     SELECT [columns] FROM table
                      INNER JOIN table2
                      ON [...]

                      INNER JOIN table3
                      ON [...]

                      LEFT JOIN table3
                      ON [...]
)
SELECT [aggregates_columns of each subset] FROM DataCTE Main
LEFT JOIN DataCTE BananasSubset
               ON [...] 
             AND Product = 'Bananas'
             AND Quality = 100
LEFT JOIN DataCTE DamagedBananasSubset
               ON [...]
             AND Product = 'Bananas'
             AND Quality < 20
LEFT JOIN DataCTE MangosSubset
               ON [...]
GROUP BY [

我感到SQL Server感到困惑,并为每个自联接调用CTE,这似乎通过查看执行计划得到了证实,尽管我承认不是阅读这些专家的专家。

我本以为SQL Server足够聪明,只能从CTE执行一次数据检索,而不是执行几次。

我尝试了相同的方法,但没有使用CTE来获取数据的子集,而是使用了与CTE中相同的选择查询,但是将其输出到临时表中。

引用CTE版本的版本需要40秒钟。引用临时表的版本需要1到2秒。

为什么SQL Server不够聪明,无法将CTE结果保存在内存中?

我喜欢CTE,在这种情况下尤其如此,因为我的UDF是表值的,因此它使我可以将所有内容保留在一个语句中。

要使用临时表,我需要编写一个多语句表,其值是UDF,但我发现它的解决方案略逊一筹。

你们中的某些人在CTE中是否遇到过此类性能问题,如果是这样,您如何对它们进行排序?

谢谢,

卡洛斯

最佳答案

我相信每次都能获得CTE结果。使用临时表,结果将被存储直到被删除。这似乎可以解释您切换到临时表时看到的性能提升。

另一个好处是,您可以在临时表上创建索引,而对cte则不能。不知道您的情况是否有好处,但是很高兴知道。

相关阅读:

  • Which are more performant, CTE or temporary tables?
  • SQL 2005 CTE vs TEMP table Performance when used in joins of other tables
  • http://msdn.microsoft.com/en-us/magazine/cc163346.aspx#S3

  • 引用最后一个链接:

    The CTE's underlying query will be called each time it is referenced in the immediately following query.



    我想说说临时表。不幸的是,优雅并不总是最好的解决方案。

    更新:

    嗯,这使事情变得更加困难。如果不查看整个环境,我很难说。

    一些想法:
  • 您可以使用存储过程代替UDF(而不是从内部)吗?
  • 这可能无法实现,但是如果您可以从CTE中删除left join,则可以将其移到索引 View 中。如果能够执行此操作,则即使在临时表上,您也可能会看到性能提升。
  • 关于sql-server - 自连接中引用的SQL Server CTE速度很慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3054843/

    相关文章:

    like和in的SQL查询组合?

    performance - MS Entity Framework 4.1中的“模型优先”和“代码优先”之间是否存在性能差异?

    PHP - 以某种方式散列对象具有相同字段值的不同对象具有相同的散列

    sql - PostgreSQL : Optimizing function with virtuals tables without "UNION SELECT"

    mysql - 增加 Mysql 变量 tmp_table_size 和 max_heap_table_size 会导致 VPS 崩溃吗?

    python - Azure函数: Can't open lib 'ODBC Driver 17 for SQL Server'

    sql - 根据加入日期和离开日期选择用户

    python - MySQLdb 为 `Decimal` 的 `sum` 返回 `INT`

    MySQL 查询包含三个表,其中一个是自引用且具有相同的字段。最好的方法是什么?

    c# - 使用 Entity Framework 防止插入对类别表的重复引用