CTE、子查询、临时表或表变量之间是否存在性能差异?

14 浏览
0 Comments

CTE、子查询、临时表或表变量之间是否存在性能差异?

在这个优秀的SO问题中,讨论了CTE子查询之间的区别。\n我想具体提问:\n在什么情况下,以下哪种方法更高效/更快?\n

    \n

  • CTE
  • \n

  • 子查询
  • \n

  • 临时表
  • \n

  • 表变量
  • \n

\n传统上,在开发存储过程时,我使用了大量的临时表,因为它们看起来比大量交织在一起的子查询更易读。\n非递归CTE非常好地封装了数据集,并且非常易读,但是在哪些特定情况下可以肯定地说它们总是表现更好?还是说必须始终尝试不同的选项,找到最高效的解决方案?\n


\n编辑\n最近有人告诉我,就效率而言,临时表是一个很好的首选,因为它们有一个关联的直方图,即统计数据。

0
0 Comments

在使用CTE、子查询、临时表或表变量时,是否存在性能差异?这个问题的出现是因为不同的方法在执行过程中可能会对性能产生不同的影响。为了解决这个问题,可以考虑以下几点:

1. CTE是一种语法结构,实际上是一个子查询。它在执行时并不会被材料化(materialized),而临时表则会被材料化。因此,在一个需要多次执行的昂贵CTE与其他表进行连接的情况下,使用临时表可能更好。而对于只需要执行几次的简单查询,则不值得使用临时表所带来的开销。

2. 有些人不喜欢使用表变量,但我喜欢它们,因为它们被材料化并且创建速度比临时表快。但在某些情况下,查询优化器可能在处理临时表时表现更好。

3. 在临时表或表变量上创建主键(PK)可以为查询优化器提供比CTE更多的信息(因为无法在CTE上声明主键)。

4. TVP是传递给存储过程的表参数的缩写。在使用表变量的人员中,TVP正变得越来越常见。简而言之,TVP就是一个作为参数传递的表。使用表变量的人对TVP应该感到很熟悉。

需要注意的是,TVP不会生成执行计划。因此,不要在TVP上执行复杂的连接、插入或更新操作,否则可能会遇到严重的优化问题。

使用CTE、子查询、临时表或表变量时,需要根据具体情况来选择合适的方法,以获得最佳的性能。

0
0 Comments

这篇文章讨论了在使用CTE、子查询、临时表或表变量时是否存在性能差异的问题。作者指出,没有一条规则可以确定哪种方法会更好,选择使用CTE主要是因为其可读性更强。但是,在某些情况下,将CTE或子查询转换为临时表可能会减少查询的执行时间。这可能是由于统计信息过期、无法获取准确的统计信息、并行处理的影响,或者查询复杂性导致无法生成最优执行计划。然而,创建临时表所涉及的I/O操作可能会抵消使用CTE的其他性能优势。总之,没有一种预测性的方法可以确定何时使用哪种方法更好,只有在实际性能问题出现时才需要改变查询方法。个人认为CTE > 子查询 > 临时表。

作者认为这个问题有很多变量,并不能提供一个“正确”的答案。只有在实际性能问题出现时才需要改变查询方法。作者建议在编写查询时选择最自然的方法,只有在发现实际性能问题时才进行调整。作者还提到,如果有特殊情况下CTE和子查询之间存在明显差异,可以提出一个新问题,附带实际查询和执行计划,以便获得更好的答案。

,选择使用CTE、子查询、临时表或表变量的性能差异取决于具体情况,需要根据实际性能问题进行选择和调整。

0
0 Comments

有没有CTE、子查询、临时表或表变量之间的性能差异?这个问题的出现的原因是因为SQL是一种声明性语言,而不是一种过程性语言,它描述了你需要的结果,而不是告诉SQL引擎如何执行工作。通常情况下,最好让SQL引擎和SQL优化器找到最佳的查询计划。然而,在某些情况下,查询计划可能不是最优的,这时你可以使用查询提示、重构查询、更新统计信息、使用临时表、添加索引等来提高性能。

关于你的问题,CTE和子查询的性能理论上应该是相同的,因为它们都向查询优化器提供相同的信息。一个区别是,多次使用的CTE可以被轻松地识别和计算一次,然后将结果存储并多次读取。不幸的是,SQL Server似乎没有利用这种基本的优化方法(你可以称之为常见子查询消除)。

临时表是不同的,因为它提供了更多关于查询如何运行的指导。一个主要的区别是优化器可以使用临时表的统计信息来建立查询计划,从而提高性能。另外,如果你有一个复杂的CTE(子查询)被多次使用,那么将其存储在临时表中通常会提高性能,查询只执行一次。

对于你的问题,你需要进行一些试验来获得你期望的性能,特别是对于经常运行的复杂查询。在理想的情况下,查询优化器会找到完美的执行路径。虽然它通常会这样做,但你可能会找到一种方法来提高性能。

关于这个问题可能会有一些微软研究的潜在改进,详见《Efficient Exploitation of Similar Subexpressions for Query Processing》。不过,这篇论文是2007年发表的,不清楚他们是否在SQL Server 2012中采纳了这些改进。

至于是否为临时表创建索引是否会提高性能,临时表上的索引确实可以提高能够利用这些索引的查询的性能,就像永久表上的索引一样。但是,如果你将子查询作为临时表实现,可能会失去原始表上索引的优势。

CTE使用多次时能够轻松识别和计算一次,但是它在所有使用的地方只运行一次吗?在SQL Server中,CTE被视为视图,并且每次引用它们时都会运行一次。然而,大多数数据库会执行你所建议的操作。

我发现一个对我有用的方法是:将重复的数据选择性地一次性插入到变量表中(而不是#临时表中),然后在需要的地方使用它。这大大减少了执行成本。正如其他朋友所说,CTE只是使我们的代码更清晰。

至于“CTE使用多次时能够轻松识别和计算一次”以及临时表由于有统计信息的保证而可能更快的观点:这只有在子查询独立于主查询的情况下才是真的。对于大多数子查询(在On或Where子句中),我发现使用子查询比CTE要快几个数量级。

没某些情况下对“争用”/“死锁”效应的影响。我们的DBA几乎总是创建临时表,主要是为了避免“争用”/“死锁”,以避免降低其他查询的性能(只有作为增加他编写的查询性能的次要原因)。他提到了他读到的一些关于如果一个查询引用了表中太多的行,SQL Server会锁定整个表的内容。我怀疑他违反了YAGNI和KISS原则,因为我曾经在更大、更频繁使用的数据库中工作过,从未需要过临时表,只要查询正确编写并对表进行了索引。

“不幸的是,SQL Server似乎没有利用这种基本的优化方法”,你知道在2020年是否仍然如此吗?

0