我正在学习表变量的更多细节。它说临时表总是在磁盘上,表变量在内存中,也就是说,表变量的性能优于临时表,因为表变量比临时表使用更少的IO操作。
但有时,如果表变量中的记录太多而无法包含在内存中,则表变量将像临时表一样放在磁盘上。
但我不知道“太多记录”是什么。 100,000条记录?或1000,000条记录?我怎么知道我正在使用的表变量是在内存中还是在磁盘上? SQL Server 2005中是否有任何函数或工具可以测量表变量的大小,或者在表变量从内存中放入磁盘时让我知道?
答案 0 :(得分:339)
您的问题表明您已经屈服于围绕表变量和临时表的一些常见误解。
我写了quite an extensive answer on the DBA site来看两种对象类型之间的差异。这也解决了你关于光盘与内存的问题(我没有看到两者之间的行为有任何显着差异)。
关于标题中的问题,关于何时使用表变量与本地临时表,您并不总是有选择。例如,在函数中,只能使用表变量,如果需要在子范围内写入表,那么只有#temp
表可以执行
(表值参数允许readonly access)。
您可以选择以下一些建议(尽管最可靠的方法是根据您的特定工作量进行测试)。
UNIQUE
或PRIMARY KEY
约束隐式创建的索引,那么您需要一个#temporary
表,因为无法在表变量上创建这些索引。 (此类索引的示例是非唯一索引,筛选索引或具有INCLUDE
d列的索引)。注意:SQL Server 2014将允许为表变量内联声明非唯一索引。#temporary
表。这支持TRUNCATE
(对于大型表来说比DELETE
更有效)并且TRUNCATE
之后的后续插入可以比DELETE
{{3}之后的后续插入更好}。#temporary
表。这支持创建统计信息,允许根据数据动态重新编译计划(尽管存储过程as illustrated here中的缓存临时表需要单独理解)。SELECT
语句,那么请考虑使用表变量将阻止使用并行计划的可能性。#temp
表时,锁可以保持比表变量更长的时间(可能直到事务结束与语句结束取决于锁和隔离级别的类型),并且它也可以防止截断tempdb
事务日志,直到用户事务结束。所以这可能有利于使用表变量。#temporary
表的元数据维护。 Bob Ward在他的the recompilation behaviour中指出,这可能会导致在高并发条件下对系统表进行额外争用。此外,在处理少量数据时,可以tempdb
presentation。行集共享的影响
DECLARE @T TABLE(id INT PRIMARY KEY, Flag BIT);
CREATE TABLE #T (id INT PRIMARY KEY, Flag BIT);
INSERT INTO @T
output inserted.* into #T
SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY @@SPID), 0
FROM master..spt_values v1, master..spt_values v2
SET STATISTICS TIME ON
/*CPU time = 7016 ms, elapsed time = 7860 ms.*/
UPDATE @T SET Flag=1;
/*CPU time = 6234 ms, elapsed time = 7236 ms.*/
DELETE FROM @T
/* CPU time = 828 ms, elapsed time = 1120 ms.*/
UPDATE #T SET Flag=1;
/*CPU time = 672 ms, elapsed time = 980 ms.*/
DELETE FROM #T
DROP TABLE #T
答案 1 :(得分:66)
如果数据量非常少(数千字节),请使用表变量
使用临时表获取大量数据
考虑它的另一种方式:如果您认为您可能从索引,自动统计或任何SQL优化器的优点中受益,那么您的数据集可能对于表变量来说太大了。
在我的示例中,我只想将大约20行放入格式中并将它们作为一组修改,然后再使用它们来更新/插入永久表。所以表变量是完美的。
但是我也在运行SQL来一次回填数千行,我可以肯定地说临时表比表变量更好地执行很多。
这与CTE是如何关注类似尺寸的原因没有什么不同 - 如果CTE中的数据非常小,我发现CTE的性能与优化器的性能一样好或更好,但如果是非常大,那会伤害你。
我的理解主要基于http://www.developerfusion.com/article/84397/table-variables-v-temporary-tables-in-sql-server/,其中有更多细节。
答案 2 :(得分:35)
Microsoft says here
表变量没有分布统计信息,它们不会触发重新编译。因此,在许多情况下,优化器将在假设表变量没有行的情况下构建查询计划。因此,如果您期望有更多行(大于100),则应谨慎使用表变量。在这种情况下,临时表可能是更好的解决方案。
答案 3 :(得分:14)
我完全同意Abacus(对不起 - 没有足够的评论意见)。
另外,请注意,它不一定归结为您拥有的记录数量,但记录的大小。
例如,您是否考虑过1,000条记录(每条记录50列)与100,000条记录(每条记录只有5列)之间的性能差异?
最后,您可能查询/存储的数据超出了您的需求吗?这是SQL optimization strategies的好读物。限制你拉动的数据量,特别是如果你没有全部使用它(一些SQL程序员确实很懒,只是选择所有内容,即使他们只使用一小部分)。别忘了SQL查询分析器也可能成为你最好的朋友。
答案 4 :(得分:4)
变量表仅适用于当前会话,例如,如果您需要EXEC
当前会话中的另一个存储过程,则必须将表作为{{1}传递当然这会影响性能,使用临时表只需传递临时表名
测试临时表:
测试变量表:
我遇到的其他事情是:如果您的架构没有Table Valued Parameter
权限来创建表,那么使用变量表。
答案 5 :(得分:3)
在声明为declare @tb
的表中写入数据,在与其他表连接后,我意识到与临时表tempdb .. # tb
相比的响应时间要高得多。
当我与 @tb 加入时,返回结果的时间要长得多,与 #tm 不同,返回几乎是瞬间的。
我使用10,000行连接进行测试,并与其他5个表连接