什么时候应该在sql server中使用表variablesvs临时表?
我正在学习表variables的更多细节。 它说临时表总是在磁盘上,表variables在内存中,也就是说,表variables的性能比临时表好,因为表variables比临时表使用更less的IO操作。
但有时,如果表variables中的logging太多,无法存储在内存中,则表variables将像临时表一样放在磁盘上。
但是我不知道“太多的logging”是什么。 100,000条logging? 还是100万条logging? 我怎么知道我使用的表variables是在内存中还是在磁盘上? 有没有在SQL Server 2005中的任何function或工具来衡量表variables的规模,或让我知道什么时候表variables从内存放在磁盘上?
你的问题表明你已经屈服于围绕表variables和临时表的一些常见的误解。
我在DBA网站上写了相当广泛的回答,看看两种对象types之间的差异。 这也解决了你关于光盘和内存的问题(我没有看到两者之间的行为有任何显着差异)。
关于标题中的问题,以及何时使用表variables与本地临时表,你并不总是有select。 例如,在函数中,只能使用表variables,如果需要在子范围内写入表,那么只有#temp
表会执行(表值参数允许只读访问 )。
你在哪里有select一些build议如下。
- 如果您需要一个不能通过
UNIQUE
或PRIMARY KEY
约束隐式创build的索引,那么您需要一个#temporary
表,因为无法在表variables上创build它们。 (这些索引的例子是非唯一索引,具有INCLUDE
d列的过滤索引或索引)。 注意:SQL Server 2014将允许为表variables内联声明非唯一索引。 - 如果您要重复添加和删除表中的大量行,请使用
#temporary
表。 这支持TRUNCATE
(对于大型表比DELETE
效率更高),另外,TRUNCATE
之后的插入可以比DELETE
之后的插入更好,如图所示 。 - 如果使用该表的最佳计划取决于数据,则使用
#temporary
表。 这支持创build统计信息,允许根据数据dynamic地重新编译计划(尽pipe对于存储过程中的caching临时表, 重新编译行为需要单独理解)。 - 如果使用表的查询的最佳计划不可能改变,那么你可以考虑一个表variables来跳过统计创build和重新编译的开销(可能需要提示来修复你想要的计划)。
- 如果插入到表中的数据的来源是来自潜在的昂贵的
SELECT
语句,那么考虑使用表variables将使用并行计划来阻止这种可能性。 - 如果需要表中的数据在外部用户事务的回滚中生存,则使用表variables。 一个可能的用例可能是在一个长SQL批处理中logging不同步骤的进度。
- 当在用户事务中使用
#temp
表时,锁可以比表variables保持更长的时间(可能直到事务的结束与语句的结束依赖于锁的types和隔离级别),也可以防止tempdb
事务的截断logging直到用户事务结束。 所以这可能有利于使用表variables。 - 在存储的例程中,可以caching表variables和临时表。 caching表variables的元数据维护less于
#temporary
表。 Bob Ward在他的tempdb
表示中指出,这可能在高并发条件下在系统表上引起额外的争用。 此外,在处理less量数据时,这可能会对性能产生显着影响 。
如果对于非常less量的数据(千字节)使用表variables ,
临时表使用大量数据
另一种思考方式:如果您认为自己可能从索引,自动统计或任何SQL优化器中获益,那么对于表variables,您的数据集可能太大。
在我的例子中,我只想将大约20行放入一个格式中,并将它们修改为一个组,然后再使用它们来更新/插入一个永久表。 所以一个表variables是完美的。
但是我也一直在运行SQL来重新填充数千行,我可以肯定地说临时表比表variables好得多。
这与CTE是如何受到类似规模的理由无关 – 如果CTE中的数据非常小,我发现CTE的performance与优化器的performance相同或更好,但是如果它相当大,它伤害你不好。
我的理解主要基于http://www.developerfusion.com/article/84397/table-variables-v-temporary-tables-in-sql-server/ ,它有更多的细节。
微软在这里说
表variables没有分布统计,他们不会触发重新编译。 因此,在许多情况下,优化器将假定表variables没有行,从而构build一个查询计划。 由于这个原因,如果期望更多的行(大于100),则应该谨慎使用表variables。 在这种情况下临时表可能是更好的解决scheme。
我完全同意Abacus(抱歉 – 没有足够的评论意见)。
另外,请记住,它不一定涉及您有多less条logging,而是logging的大小 。
例如,您是否考虑过每个logging有50列的1,000条logging与仅有5列的100,000条logging之间的性能差异?
最后,也许你正在查询/存储更多的数据比你需要? 这里有一个很好的SQL优化策略的阅读。 限制你正在使用的数据量,特别是如果你不使用所有的数据(一些SQL程序员确实懒惰,只select一切,即使他们只使用一小部分)。 不要忘记,SQL查询分析器也可能成为你最好的朋友。
variables表仅适用于当前会话,例如,如果您需要在当前会话中EXEC
另一个存储过程,则必须将该表作为Table Valued Parameter
传递,当然这会影响性能,您可以使用临时表这样做只通过临时表名称
testing临时表:
- 打开pipe理工作室查询编辑器
- 创build一个临时表
- 打开另一个查询编辑窗口
- 从此表中select“可用”
要testingvariables表:
- 打开pipe理工作室查询编辑器
- 创build一个variables表
- 打开另一个查询编辑窗口
- 从此表中select“不可用”
我遇到的其他事情是:如果您的模式没有GRANT
权限来创build表,然后使用variables表。 此外,位于tempdb数据库和表variables中的临时表可以位于内存和tempdb数据库的磁盘上。 看到这里: https : //www.linkedin.com/pulse/highlighted-differences-between-sql-server-temporary-tables-andrew
在声明declare @tb
表中写入数据,并且在join其他表之后,我意识到响应时间与临时表tempdb .. # tb
相比要高得多。
当我用@tb连接它们时,返回结果的时间要长得多,不像#tm ,返回几乎是瞬间的。
我做了10,000行jointesting,并join了5个其他表