我什么时候应该在sql server中使用表变量和临时表?

2024-03-31

我正在表变量中了解更多详细信息。它说临时表总是在磁盘上,而表变量在内存中,也就是说,表变量的性能比临时表更好,因为表变量比临时表使用更少的IO操作。

但有时,如果表变量中的记录太多而无法容纳在内存中,则该表变量将像临时表一样放在磁盘上。

但我不知道“记录太多”是什么。 100,000 条记录?或 1000,000 条记录?我如何知道我正在使用的表变量是在内存中还是在磁盘上? SQL Server 2005中是否有任何函数或工具可以测量表变量的规模或让我知道表变量何时从内存放入磁盘?


您的问题表明您已经屈服于有关表变量和临时表的一些常见误解。

我已经写了DBA 网站上有相当广泛的答案 https://dba.stackexchange.com/questions/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386#16386查看两种对象类型之间的差异。这也解决了您关于磁盘与内存的问题(我没有看到两者之间的行为有任何显着差异)。

关于标题中的问题,关于何时使用表变量与本地临时表,您并不总是有选择。例如,在函数中,只能使用表变量,如果需要在子作用域中写入表,则只能使用表变量#temp表就可以了 (表值参数允许只读访问 https://stackoverflow.com/questions/4626292/how-to-use-table-variable-in-a-dynamic-sql-statement/12876775#12876775).

如果您确实可以选择,下面列出了一些建议(尽管最可靠的方法是简单地根据您的特定工作负载测试两者)。

  1. 如果您需要一个无法在表变量上创建的索引,那么您当然需要一个#temporary桌子。然而,其细节取决于版本。对于 SQL Server 2012 及更低版本,可以在表变量上创建的唯一索引是通过隐式创建的索引UNIQUE or PRIMARY KEY约束。 SQL Server 2014 为可用选项的子集引入了内联索引语法CREATE INDEX。此后这一点已得到扩展,以允许过滤索引条件。索引与INCLUDE但是,仍然无法在表变量上创建 -d 列或列存储索引。

  2. 如果您要从表中重复添加和删除大量行,请使用#temporary桌子。那支持TRUNCATE(这比DELETE对于大表)以及随后的后续插入TRUNCATE可以比遵循以下方法的人有更好的表现DELETE 如图所示 https://dba.stackexchange.com/questions/27309/why-does-delete-leave-a-lingering-effect-on-performance/27319#27319.

  3. 如果您要删除或更新大量行,那么临时表的性能可能会比表变量好得多 - 如果它能够使用行集共享(请参阅下面的“行集共享的影响”示例)。
  4. 如果使用该表的最佳计划将根据数据而变化,则使用#temporary桌子。支持创建统计信息,允许根据数据动态重新编译计划(尽管对于存储过程中的缓存临时表)重新编译行为 http://web.archive.org/web/20180130201242/http://sqlblog.com/blogs/paul_white/archive/2012/08/15/temporary-tables-in-stored-procedures.aspx需要单独理解)。
  5. 如果使用表的查询的最佳计划不太可能改变,那么您可以考虑使用表变量来跳过统计信息创建和重新编译的开销(可能需要提示来修复您想要的计划)。
  6. 如果插入表的数据源来自潜在昂贵的SELECT语句然后考虑使用表变量将阻止使用并行计划的可能性。
  7. 如果您需要表中的数据在外部用户事务回滚后仍然存在,那么请使用表变量。一个可能的用例可能是记录长 SQL 批处理中不同步骤的进度。
  8. 当使用#temp用户事务中的表锁可以比表变量持有更长时间(可能直到事务结束或语句结束,具体取决于锁的类型和隔离级别),并且它还可以防止截断tempdb事务日志直到用户事务结束。因此这可能有利于使用表变量。
  9. 在存储例程中,表变量和临时表都可以被缓存。缓存表变量的元数据维护比#temporary表。鲍勃·沃德在他的tempdb推介会 http://www.youtube.com/watch?v=SvseGMobe2w在高并发的情况下,这可能会导致系统表出现额外的争用。此外,在处理少量数据时,这可以使性能上有可衡量的差异 https://dba.stackexchange.com/a/13412/3690.

行集共享的影响

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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我什么时候应该在sql server中使用表变量和临时表? 的相关文章

  • 尝试将 Asp.Net Memebership 数据库部署到 SQL Azure

    我一直在尝试让 ASP net 会员服务提供商与托管在 SQL Azure 中的其余数据库配合使用 我已针对数据库运行适当的 SQL Azure 特定脚本来进行设置 这些脚本可从 Microsoft 获取 http archive msdn
  • TSQL如何在xml列中选择具有技能的员工

    在如下所示的表架构中 CREATE TABLE dbo Employee EmployeeId uniqueidentifier NOT NULL Name nvarchar 50 NOT NULL Location nvarchar 50
  • 避免数据集中出现重复名称

    我正在从表中获取数据并绑定到标签并在 gridview 中下拉 但我想从表中过滤重复的名称并将相应的日期分配给 DDL 如何做到这一点 或者还有其他选择吗 private DataSet get string sql select Id N
  • SQL Server:触发器如何读取插入、更新、删除的值

    我在一张表中有触发器并且想阅读UserId插入 更新或删除行时的值 怎么做 下面的代码不起作用 我收到错误UPDATED ALTER TRIGGER dbo UpdateUserCreditsLeft ON dbo Order AFTER
  • asp.net网格分页的SQL查询

    我在用iBatis and SQLServer 使用偏移量和限制进行分页查询的最佳方法是什么 也许我添加该列ROW NUMBER OVER ORDER BY Id AS RowNum 但这只会阻止简单查询的数据访问 在某些情况下 我使用选择
  • 存储过程总是返回0

    我试图从存储过程获取返回值 但它总是返回 0 c code cmd new SqlCommand cmd CommandType CommandType StoredProcedure cmd CommandText AbsentEntry
  • 更新列的脚本

    表名 公民 Firstname Lastname Telephone1 Many other columns John Smith 03907625212 Andrew Evans 0807452132 Bill Towny 0590712
  • 获取一组记录之间的时间差

    我有一个具有以下结构的表 ID ActivityTime Status 19 2013 08 23 14 52 1 19 2013 08 23 14 50 1 19 2013 08 23 14 45 2 19 2013 08 23 14 3
  • 从 SQL Server 读取十进制值时出现溢出异常

    我想知道这是一个错误还是我做错了什么 我正在加载值SqlDataReader来自 SQL Server 2008 数据库 但在某些情况下 它无法将 SQL 值转换为 net 值 NET 4 0 我已将其追溯到一个测试用例 它演示了实际问题
  • 如何使用sql脚本更改列的属性

    如何使用 sql 脚本更改列的属性 这是我尝试过但出现错误的方法 ALTER TABLE dbo tblBiometricPattern COLUMN BiometricPatternID TINYINT NOT NULL IDENTITY
  • 如何在事务中使用链接服务器插入远程表?

    我的链接服务器设置正确 我能够执行以下查询 插入 远程服务器 表 SELECT FROM 本地服务器 表 然而当我做同样的事情时交易内 开始传输 插入 远程服务器 表 SELECT FROM 本地服务器 表 提交交易 我收到类似的错误 用于
  • SQL Server中的列级与表级约束?

    A 列级 GO CREATE TABLE Products ProductID INT CONSTRAINT pk products pid PRIMARY KEY ProductName VARCHAR 25 GO b 表层 CREATE
  • Sql Server 的夏令时

    我们正在使用一个以 C Unix 格式存储日期的旧应用程序 C 时间基本上是自 1970 年 1 月 1 日以来的秒数 日期以整数形式存储在 SQL Server 数据库中 我正在为使用这些日期的报告编写视图 到目前为止 我正在使用以下命令
  • 合并sql中的列

    我正在使用 SQL Server 2017 有一个存储过程 其中我有一个带有连接的简单选择 例如 SELECT p legacyKey AS JobNumber p Name AS JobName G Label AS DesignStat
  • 将 MSSQL 中用于 Web 制图的投影(Leaflet、Openlayer、OpenStreetMaps、GoogleAPI...)更改为 WSG48 或任何其他格式

    我在 MSSQL 服务器中有一些像这样的 WKT WKB 数据 并希望借助 leaflet Openlayer OpenStreetMaps 或 GoogleAPI 将它们显示在地图上 我的数据如下所示 POLYGON 1736946 09
  • SQL Server 2008 错误 233

    我正在使用以下 sql 脚本在 SQL Server 2008 中创建新登录名 CREATE LOGIN xyz WITH PASSWORD xyz DEFAULT DATABASE master DEFAULT LANGUAGE us e
  • 分组和切换列和行

    我不知道这是否会被正式称为枢轴 但我想要的结果是这样的 Alex Charley Liza 213 345 1 23 111 5 42 52 2 323 5 23 1 324 5 我的输入数据采用这种形式 Apt Name
  • 一个表可以有多个主键吗?

    我现在很困惑 也许你可以帮助我更好地理解这个问题 即一个表可以有两个主键 如果是 那么如何 如果没有 那为什么 您询问是否可以有多个主键field你当然可以 您只能有一个主键 但它可以包含唯一标识行所需的任意数量的列 创建表时使用类似这样的
  • 从字符串中删除某些字符

    我正在尝试删除某些字符 目前我的输出如下cityname district但我想删除cityname SELECT Ort FROM dbo tblOrtsteileGeo WHERE GKZ 06440004 Output B dinge
  • NVARCHAR 变量在Where 子句中不起作用

    在 SQL Server 我想是 2018 我不知道如何判断 中 我的变量不起作用WHERE的条款NVARCHAR 比较应该返回值 但它什么也没返回 如果我只是手动输入声明的文本 它会突然起作用并返回值 没有任何逻辑原因应该有任何不同 类型

随机推荐