什么时候应该在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议如下。

  1. 如果您需要一个不能通过UNIQUEPRIMARY KEY约束隐式创build的索引,那么您需要一个#temporary表,因为无法在表variables上创build它们。 (这些索引的例子是非唯一索引,具有INCLUDE d列的过滤索引或索引)。 注意:SQL Server 2014将允许为表variables内联声明非唯一索引。
  2. 如果您要重复添加和删除表中的大量行,请使用#temporary表。 这支持TRUNCATE (对于大型表比DELETE效率更高),另外, TRUNCATE之后的插入可以比DELETE之后的插入更好,如图所示 。
  3. 如果使用该表的最佳计划取决于数据,则使用#temporary表。 这支持创build统计信息,允许根据数据dynamic地重新编译计划(尽pipe对于存储过程中的caching临时表, 重新编译行为需要单独理解)。
  4. 如果使用表的查询的最佳计划不可能改变,那么你可以考虑一个表variables来跳过统计创build和重新编译的开销(可能需要提示来修复你想要的计划)。
  5. 如果插入到表中的数据的来源是来自潜在的昂贵的SELECT语句,那么考虑使用表variables将使用并行计划来阻止这种可能性。
  6. 如果需要表中的数据在外部用户事务的回滚中生存,则使用表variables。 一个可能的用例可能是在一个长SQL批处理中logging不同步骤的进度。
  7. 当在用户事务中使用#temp表时,锁可以比表variables保持更长的时间(可能直到事务的结束与语句的结束依赖于锁的types和隔离级别),也可以防止tempdb事务的截断logging直到用户事务结束。 所以这可能有利于使用表variables。
  8. 在存储的例程中,可以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个其他表