SQL Server 临时表和表变量系列之踢馆篇

摘要

在面对SQL Server选择使用临时表还是表变量作为数据暂存问题时,有一个非常重要的选择标准便是性能,两者对于查询语句和DML性能表现到底如何呢?我相信,很多人的认识是片面的,或者是错误的。这里以一篇引用率很高的文章来作为反面教材来纠正那些片面和错误的认识,我暂且称之为“踢馆”。

背景

在研究临时表和表变量该如何选择的时候,一篇文章叫着SQL Server Temp Table vs Table Variable Performance Testing文章引用率是非常高的。通读全文,作者褒“临时表”贬“表变量”的语调跃然纸上,虽然原作者也有唯物辩证的思维去看待这个问题。但,综合起来原作者认为临时表性能好于表变量。事实上真的是这样子的吗?这篇文章会一探究竟。

分析

首先,原作者的测试环境的搭建存在漏洞,非常不严谨。体现在作者为临时表在col2上创建了非聚集索引,而表变量上的col2上没有定义非聚集索引。根据生物学对比试验方法论,实验组与对比组只允许有一个变化的影响因素,但是原作者这里引入了两个变化因素:第一是临时表和表变量;第二个变化因素是临时表具有索引,而表变量没有索引。这可能是因为作者认为表变量不能够创建索引,证据在原作者的这句话“However, when we query rows using the indexed column of the temporary table, which is not indexed in the table variable since this is not available for table variables, we see a really big increase in performance across all measures for the temporary table. ”,但实际上表变量同样是可以创建索引的,只不过必须是在定义表变量的同时创建索引,定义结束后,不支持对表变量的任何修改。详情可以参见文章SQL Server 临时表和表变量系列之认知误区篇。由于作者的这个认识误区,导致了整个测试结果不严谨,结论不够准确,给了读者踢馆的机会。
原作者对临时表创建的两个索引:

-- Create index logic
CREATE NONCLUSTERED INDEX [IX_temptable] ON #temptable ([col2] ASC)
CREATE NONCLUSTERED INDEX [IX_bigtemptable] ON #bigtemptable ([col2] ASC)

测试

毛爷爷说:“实践出真知,没有调查就没有发言权。”,我们按照原作者的思路,纠正作者测试环境搭建的疏漏,然后再来测试INSERT、SELECT、UPDATE和DELETE操作性能。为两个表变量在col2上创建索引,定义表变量时,添加了语句index IX_col2(col2 ASC)。代码如下:

-- Table creation logic
CREATE TABLE #temptable ([col1] [int] NOT NULL primary key,[col2] [int] NULL,
[col3] [int] NULL,[col4] [varchar](50) NULL)
DECLARE @tablevariable TABLE ([col1] [int] NOT NULL primary key,[col2] [int] NULL,
[col3] [int] NULL,[col4] [varchar](50) NULL, index IX_col2(col2 ASC))
CREATE TABLE #bigtemptable ([col1] [int] NOT NULL primary key,[col2] [int] NULL,
[col3] [int] NULL,[col4] [varchar](50) NULL)
DECLARE @bigtablevariable TABLE ([col1] [int] NOT NULL primary key,[col2] [int] NULL,
[col3] [int] NULL,[col4] [varchar](50) NULL, index IX_col2(col2 ASC))
-- Create index logic
CREATE NONCLUSTERED INDEX [IX_temptable] ON #temptable ([col2] ASC)
CREATE NONCLUSTERED INDEX [IX_bigtemptable] ON #bigtemptable ([col2] ASC)

保持其他的地方原封不动,在一个连接中,执行所有的语句。

INSERT语句性能对比

原作者对INSERT语句测试结果截图如下:

原作者得出的结论:“This can probably be attributed to the fact that the temporary table has an extra index on the table that needs to be updated as well.”
这个结论不攻自破了,由于作者没有对表变量创建索引,所以会认为临时表的索引导致了插入效率比表变量低。来看看纠正了测试环境的错误后的测试结果:

从这个测试结果来看,表变量有一条插入语句比临时表更慢;另一条插入语句两者性能相当。

SELECT语句性能对比

原作者对SELECT语句测试结果的截图如下(我用红色长方形框标记了对比之处):

还是由于原作者对表变量没有创建索引,导致通过col2条件查询表变量的时候,得出的测试结论不正确:使用临时表的时间消耗为1毫秒,使用表变量时间消耗为99毫秒,临时表效率更高。我的测试结果截图如下:

从我的测试接过来看,使用临时表的时间消耗为626毫秒,而使用表变量的时间消耗仅为100毫秒,表变量效率更高,这个和原作者的结论恰好相反。

UPDATE语句性能对比

UPDATE语句由于原作者截图中无法看到执行时间消耗。所以,我们采用CPU和Reads来对比:原测试使用表变量在CPU和IO读两个方面相对于临时表性能消耗更高,效率更低。

而我们的测试结果恰好相反,两者在CPU方面相当,均为0,而IO读取方面,表变量性能更高,与原作者结论恰好相反。得出这个测试结果的原因还是因为为表变量创建了索引。

DELETE语句性能对比

原作者对DELETE语句测试的截图如下。由截图来看,表变量在CPU消耗,IO读取和执行时间消耗三个层面,性能消耗相对于临时表都更高,效率都更低。

而我们的测试结果截图如下:临时表CPU消耗更严重,IO读表变量更高,执行时间表变量稍微高一点,1毫秒的差异几乎可以忽略不计。

总结

之所谓“差之毫厘谬以千里”,由于原作者忽略了对表变量定义索引,亦或者是不知道为表变量创建索引,导致整个性能对比测试不严谨,测试结果和事实大相径庭,给了我们踢馆的机会。

时间: 2024-08-02 23:14:07

SQL Server 临时表和表变量系列之踢馆篇的相关文章

SQL Server 临时表和表变量系列之选择篇

摘要 通过前面的三篇系列文章,我们对临时表和表变量的概念.对比和认知误区已经有了非常全面的认识.其实,我们的终极目的,还是今天要讨论的话题,即当我们面对具体的业务场景的时候,该选择临时表还是表变量? 几种典型场景 以下是几种典型的场景,让我们看看到底该作何选择,以及做出最终选择的具体原因和考量. 存储过程嵌套 在SQL Server中,使用存储过程的好处显而易见,往往会节约存储过程执行计划编译时间,提高查询语句的执行效率.有时候,我们在构建存储过程多层次嵌套场景中,会有内层存储过程需要临时使用外

再议SQL Server临时表和表变量

今天在我和一家软件公司的开发人员讨论数据库设计调优的时候又讨论到了表变量和临时表的问题,觉得这个问题确实是一个争议比较大的问题. 其实从上次发表了表变量和临时表的一个帖子http://database.ctocio.com.cn/tips/442/8206442.shtml以来,也有些人留言,也有些人发过邮件讨论这个问题.其实表变量和临时表的区别虽然有一些,但是两者最根本的区别还是在于 对存储的需求:表变量和临时表都消耗Tempdb中的存储空间,但是进行数据更新的时候,表变量不会写日志,而临时表

SQL Server 临时表和变量系列之对比篇

摘要 在SQL Server代码编写过程中,经常会有需要临时"暂存"一部分数据结果集,供上下文使用,这个时候,我们有两种选择,即临时表和表变量.这篇文章从以下几个方面来对临时表和表变量进行对比: 创建和析构方式 存储方式 作用域 对事务的支持 性能影响 创建和析构方式 临时表和表变量在创建和析构方式上是完全不一样的,在这一节,我们会从以下几点来看看他们的不同. 结构定义 索引创建 DDL 析构方式 结构定义 在上一篇文章SQL Server 临时表和变量系列之概念篇中

SQL Server中临时表与表变量有什么区别

我们在数据库中使用表的时候,经常会遇到两种使用表的方法,分别就是使用临时表及表变量.在实际使用的时候,我们如何灵活的在存储过程中运用它们,虽然它们实现的功能基本上是一样的,可如何在一个存储过程中有时候去使用临时表而不使用表变量,有时候去使用表变量而不使用临时表呢? 临时表 临时表与永久表相似,只是它的创建是在Tempdb中,它只有在一个数据库连接结束后或者由SQL命令DROP掉,才会消失,否则就会一直存在.临时表在创建的时候都会产生SQLServer的系统日志,虽它们在Tempdb中体现,是分配

SQL Server中临时表与表变量的区别

  我们在数据库中使用表的时候,经常会遇到两种使用表的方法,分别就是使用临时表及表变量.在实际使用的时候,我们如何灵活的在存储过程中运用它们,虽然它们实现的功能基本上是一样的,可如何在一个存储过程中有时候去使用临时表而不使用表变量,有时候去使用表变量而不使用临时表呢? 临时表 临时表与永久表相似,只是它的创建是在Tempdb中,它只有在一个数据库连接结束后或者由SQL命令DROP掉,才会消失,否则就会一直存在.临时表在创建的时候都会产生SQLServer的系统日志,虽它们在Tempdb中体现,是

【T-SQL系列】临时表、表变量

原文:[T-SQL系列]临时表.表变量 临时表临时表与永久表相似,只是它的创建是在Tempdb中,它只有在一个数据库连接结束后或者由SQL命令DROP掉,才会消失,否则就会一直存在.临时表在创建的时候都会产生SQL Server的系统日志,虽它们在Tempdb中体现,是分配在内存中的,它们也支持物理的磁盘,但用户在指定的磁盘里看不到文件. 临时表分为本地和全局两种,本地临时表的名称都是以"#"为前缀,只有在本地当前的用户连接中才是可见的,当用户从实例断开连接时被删除.全局临时表的名称都

SQL Server-聚焦事务对本地变量、临时表、表变量影响以及日志文件存满时如何收缩(三十一)

前言 接下来我们将SQL Server基础系列还剩下最后几节内容结束,后续再来讲解SQL Server性能调优,我们开始进入主题. SQL Server事务对本地变量影响 事务对变量影响具体是指什么意思呢,换句话说就是当我们回滚事务和提交事务之后对本地变量是否起作用呢,下面我们来看下具体例子. PRINT '回滚事务之后测试' DECLARE @FlagINT INT SET @FlagInt = 1 PRINT @FlagInt ---- 此时变量值为1 BEGIN TRANSACTION S

sql server中判断表或临时表是否存在的方法_MsSql

1.判断数据表是否存在 方法一: use yourdb; go if object_id(N'tablename',N'U') is not null print '存在' else print '不存在' 例如: use fireweb; go if object_id(N'TEMP_TBL',N'U') is not null print '存在' else print '不存在' 方法二: USE [实例名] GO IF EXISTS (SELECT * FROM dbo.SysObjec

sqlserver 临时表 Vs 表变量 详细介绍_MsSql

这里我们在SQL Server 2005\SQL Server 2008版本上通过举例子,说明临时表和表变量两者的一些特征,让我们对临时表和表变量有进一步的认识.在本章中,我们将从下面几个方面去进行描述,对其中的一些特征举例子说明: 约束(Constraint) 索引(Index) I/0开销 作用域(scope) 存儲位置 其他   例子描述 约束(Constraint)            在临时表和表变量,都可以创建Constraint.针对表变量,只有定义时能加Constraint.