【问题标题】:Difference between CTE, Temp Table and Table Variable in MSSQLMSSQL中CTE、临时表和表变量的区别
【发布时间】:2017-05-27 17:55:01
【问题描述】:

全部用于临时存储数据。

这 3 种类型的临时表有性能差异(时间复杂度和空间复杂度)吗?

性能问题应该取决于结果是保存在磁盘还是内存中。

我搜索了很多,但没有得到满意的答案。

【问题讨论】:

  • 表变量本质上也是临时的,但与临时表不同。如果需要性能,则临时表几乎总是会胜过表变量。 What's the difference between a temp table and table variable in SQL Server?
  • 请记住,当没有足够的内存来保存数据时,其中任何一个都可以并且将会保存在磁盘上。这是一个非常普遍的误解。这是 tempdb 的主要用途之一,用于保存从内存溢出的数据。
  • 不要在这里尝试学习“始终使用 X 以获得最佳性能”的规则。使用与您的其余代码最自然匹配的任何内容。然后,如果表现很重要,设定目标,衡量表现,如果你没有达到目标,分析热点和衡量备选方案。
  • @NoorAshuvo 这完全取决于您的场景、服务器、运行查询时的资源使用情况、您“处理”的数据量或仅返回的数据,你正在使用什么数据类型,你做了多少计算等等(只是为了开始)。 Damien_The_Unbeliever 的答案至少是您应该从这里的所有信息中记住的一件事。

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


【解决方案1】:

CTE - 公用表表达式 CTE 代表公用表表达式。它是在 SQL Server 2005 中引入的。它是一个临时结果集,通常可能是复杂子查询的结果。与临时表不同,它的生命周期仅限于当前查询。它是使用 WITH 语句定义的。 CTE 提高了复杂查询和子查询的可读性和易于维护。始终以分号开头 CTE。

With CTE1(Address, Name, Age)--Column names for CTE, which are optional
AS
(
SELECT Addr.Address, Emp.Name, Emp.Age from Address Addr
INNER JOIN EMP Emp ON Emp.EID = Addr.EID
)
SELECT * FROM CTE1 --Using CTE 
WHERE CTE1.Age > 50
ORDER BY CTE1.NAME

何时使用 CTE? 这用于存储复杂子查询的结果以供进一步使用。

这也用于创建递归查询。

临时表 在 SQL Server 中,临时表是在运行时创建的,您可以执行在普通表上可以执行的所有操作。这些表是在 Tempdb 数据库中创建的。根据范围和行为,临时表有两种类型,如下所示-

本地临时表 本地临时表仅适用于创建表的 SQL Server 会话或连接(意味着单个用户)。当创建表的会话关闭时,这些会自动删除。本地临时表名以单井号(“#”)开头。

CREATE TABLE #LocalTemp
(
 UserID int,
 Name varchar(50), 
 Address varchar(150)
)
GO
insert into #LocalTemp values ( 1, 'Shailendra','Noida');
GO
Select * from #LocalTemp

Local temp table 的范围存在于当前用户的当前会话中,即存在于当前查询窗口中。如果您将关闭当前查询窗口或打开一个新的查询窗口并尝试查找上面创建的临时表,则会出现错误。

全局温度表 全局临时表可用于所有 SQL Server 会话或连接(意味着所有用户)。这些可以由任何 SQL Server 连接用户创建,并在所有 SQL Server 连接关闭后自动删除。全局临时表名以双井号(“##”)开头。

CREATE TABLE ##GlobalTemp
(
 UserID int,
 Name varchar(50), 
 Address varchar(150)
)
GO
insert into ##GlobalTemp values ( 1, 'Shailendra','Noida');
GO
Select * from ##GlobalTemp

全局临时表对所有 SQL Server 连接可见,而本地临时表仅对当前 SQL Server 连接可见。

表变量 这就像一个变量,存在于特定批次的查询执行中。一旦它从批次中出来,它就会被丢弃。这也是在 Tempdb 数据库中创建的,但不是在内存中创建的。这也允许您在表变量声明时创建主键、标识而不是非聚集索引。

 GO
 DECLARE @TProduct TABLE
 (
 SNo INT IDENTITY(1,1),
 ProductID INT,
 Qty INT
 ) 
 --Insert data to Table variable @Product 
 INSERT INTO @TProduct(ProductID,Qty)
 SELECT DISTINCT ProductID, Qty FROM ProductsSales ORDER BY ProductID ASC 
 --Select data
 Select * from @TProduct

 --Next batch
 GO
 Select * from @TProduct --gives error in next batch

注意 临时表是在 Tempdb 数据库中物理创建的。这些表充当普通表,也可以像普通表一样有约束、索引。

CTE 是一个命名的临时结果集,用于操作复杂的子查询数据。这存在于声明的范围内。这是在内存而不是 Tempdb 数据库中创建的。您不能在 CTE 上创建任何索引。

表变量就像一个变量,存在于特定批次的查询执行中。一旦它从批次中出来,它就会被丢弃。这也是在 Tempdb 数据库中创建的,但不是在内存中创建的。

【讨论】:

【解决方案2】:

涵盖所有细节的相当广泛的主题。以下是一些高级差异,它们可以为您提供更多研究思路。

CTE 是同一查询的一部分,应该被认为与子查询非常相似。 CTE 允许更好的可读性和代码重用(相同的 CTE 可以在整个查询的不同部分重用)。

表变量和临时表应该被认为是类似的真实表,但经过优化后,SQL Server 可以快速对它们进行操作,尤其是在用于相对较小的数据集时。请注意,尽管这些对 tempdb 进行操作,但这并不意味着此处存储的数据实际上已保存到磁盘。对于每个新版本的 SQL Server,都进行了额外的优化(例如内存优化表),以使这些构造更快,特别是对于简化复杂查询的主线用例。

有关此主题的更多信息,请参阅此处: https://www.brentozar.com/archive/2014/06/temp-tables-table-variables-memory-optimized-table-variables/

【讨论】:

    猜你喜欢
    • 2015-11-09
    • 2010-09-06
    • 2013-08-07
    • 2022-01-09
    • 2011-07-15
    • 1970-01-01
    • 2016-07-19
    • 2019-11-21
    • 2017-06-27
    相关资源
    最近更新 更多