【问题标题】:SQL Server - Table variable vs temporary table with a select statement with unionSQL Server - 表变量与带有联合选择语句的临时表
【发布时间】:2017-01-26 13:18:47
【问题描述】:

我需要从一个复杂的选择查询中创建一些连接列,该查询是三个选择的联合

SELECT C1,C2, ... FROM Source1
UNION
SELECT C1,C2,... FROM Source2
UNION
SELECT C1,C2 from Source3

现在,我没有在所有三个选择语句中重复我的新列的生成逻辑,而是考虑使用表变量来临时存储联合结果并将我的列添加到从表变量中选择的列中。所以像

DECLARE @tv TABLE
(C1 varchar(max),
C2 varchar(max)
.
.
.)

INSERT INTO @tv
SELECT C1,C2, ... FROM Source1
UNION
SELECT C1,C2,... FROM Source2
UNION
SELECT C1,C2 from Source3

SELECT 
C1,
C2,
CASE WHEN ...
ELSE ''
END CN
FROM @tv

我已阅读有关使用表变量时要注意的性能注意事项。上面的查询有时可能会生成几千行,但在大多数情况下会生成几百行。在这种情况下切换到临时变量会更好吗? UNION SELECT 语句是否仍然能够并行运行?

【问题讨论】:

  • 除非你有谓词,否则我看不到问题
  • 为什么不只使用 CTE,甚至是视图?
  • 此查询在存储过程中,因此视图不起作用
  • 如果我唯一的选择是临时表或表变量,我会选择临时表,除非数据集非常小并且我没有加入任何其他表。 table variables vs temp tables - Richard Douglas.

标签: sql sql-server sql-server-2008


【解决方案1】:

将列生成逻辑放在一个地方是个好主意。我会用一个子查询来做到这一点:

SELECT s.*,
       (CASE WHEN ...
        ELSE ''
        END) as CN
FROM (SELECT C1,C2, ... FROM Source1
      UNION ALL
      SELECT C1,C2,... FROM Source2
      UNION ALL
      SELECT C1,C2 from Source3
     ) s;

注意:请使用UNION ALL 而不是UNION,除非您特别想承担删除重复项的开销。

【讨论】:

  • 更准确地说,这是一个派生表。
  • 这与 CTE 答案一样正确。所以让我只接受一个答案,所以我对这个答案投了赞成票。谢谢戈登。
【解决方案2】:

另一种选择是使用 CTE,按照您描述的方式,这几乎就是 CTE 的用途:

;WITH cte as
(
    SELECT C1,C2, ... FROM Source1
    UNION ALL
    SELECT C1,C2,... FROM Source2
    UNION ALL
    SELECT C1,C2 from Source3
) 
SELECT cte.*,
       (CASE WHEN ...
        ELSE ''
        END) as CN
FROM cte;

但围绕 CTE 与表 var 与临时表需要考虑一些事项:

tl;dr: CTE 可在单个查询中重复使用,表变量和临时表可在许多查询中重复使用,并且具有一些不同的内存/索引功能。)

  • CTE 可在您的查询中重复使用,并且最终可能比子查询更简洁,但有些人只是习惯于子查询。在某些情况下,我发现优化器在 CTE 上比在子查询上做得更好,但它通常会成功。
  • 表变量可以存储在内存或磁盘中; CTE 基本上也以这种方式工作,但最大的区别是表变量可以添加主键和唯一键。你在这里没有使用它,所以没什么大不了的。另一个很大的区别是表变量可以声明为可重用类型 - 如果这是您在很多地方使用的格式并且想要维护它的结构,那将很有帮助。如果您使用的是 SQL 2014 或 2016,这也很有帮助,其中表变量可以在内存表中声明为 OLTP。临时表不能做到这一点,CTE 也不能——这基本上是一个非常优化的表版本,适用于高争用场景,在内存中使用无锁结构而不是正常的 SQL 锁过程更好地处理这些场景。表变量也可以作为参数传递给其他存储过程。
  • 临时表可以添加任意数量的索引。它们也可以声明为全局临时表。它们将驻留在磁盘上,并将工作添加到您的 tempdb。它们不能在内存 OLTP 表中声明。它们不能作为参数传递,但可以在过程之间共享(无论是作为全局临时表还是作为同一批次中可访问的临时表)
  • 临时变量和表变量都可以在初始 INSERT 之后运行其他 DML 语句 - 如果您需要在其中更新/删除/插入更多可以工作的数据。 CTE 无法做到这一点(如果您在 CTE 上运行 DML,它将插入/更新/删除基础表)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-08
    • 2011-12-22
    • 1970-01-01
    • 2018-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多