当前位置: 首页 > 编程日记 > 正文

【译】表变量和临时表的比较(转)

关于表变量是什么(和表变量不是什么),以及和临时表的比较让很多人非常困惑。虽然网上已经有了很多关于它们的文章,但我并没有发现一篇比较全面的。在本篇文章中,我们将探索表变量和临时表是什么(以及不是什么),然后我们通过使用临时表和表变量对其解密。

表变量

表变量在SQL Server 2000中首次被引入,那么,什么是表变量呢?微软在BOL (Declare @local_variable)中定义其为一个类型为表的变量。它的具体定义包括列定义,列名,数据类型和约束。而在表变量中可以使用的约束包括主键约束,唯一约束,Null约束和Check约束(外键约束不能在表变量中使用).定义表变量的语句是和正常使用Create table定义表语句的子集。只是表变量通过DECLARE @local_variable 语句进行定义。

通过参考1可以知道:

1) 表变量拥有特定作用域(在当前批处理语句中,但不在任何当前批处理语句调用的存储过程和函数中),表变量在批处理结束后自动被清除。

2) 参考6中在"Recompilations Due to Certain Temporary Table Operations" 环节讨论了临时表在会导致存储过程强制被重复编译的各种原因,但这些原因并不适用于表变量。表变量和临时表比起来会产生更少的存储过程重编译。

3) 针对表变量的事务仅仅在更新数据时生效,所以锁和日志产生的数量会更少。

4) 由于表变量的作用域如此之小,而且不属于数据库的持久部分,所以事务回滚不会影响表变量。

表变量可以在其作用域内像正常的表一样使用。更确切的说,表变量可以被当成正常的表或者表表达式一样在select,delete,update,insert语句中使用。但是表变量不能在类似“SELECT select_list INTO table_variable” 这样的语句中使用。而在SQL Server 2000中,表变量也不能被用于“INSERT INTO table_variable EXEC stored_procedure”这样的语句中。

表变量不能做如下事情:

1.虽然表变量是一个变量,但是其不能赋值给另一个变量。

2.check约束,默认值,和计算列不能引用自定义函数。

3.不能为约束命名。

4.不能Truncate表变量

5.不能向标识列中插入显式值(也就是说表变量不支持SET IDENTITY_INSERT ON)

临时表

在深入临时表之前,我们首先需要讨论一下会话(Session),一个会话仅仅是一个客户端到数据引擎的连接。在SQL Server Management Studio(SSMS)中,每一个查询窗口都会和数据库引擎建立连接。一个应用程序可以和数据库建立一个或多个连接,除此之外,应用程序还可能建立连接后一直不释放直到应用程序结束,也可能使用完释放连接需要时建立连接。

那么,什么是临时表?在BOL (CREATE TABLE)中,我们可以知道临时表和以Create table语句创建的表有着相同的物理构成,但临时表与正常的表不同之处有:

1) 临时表的名字不能超过116个字符,这是由于数据库引擎为了辨别不同会话建立不同的临时表,所以会自动在临时表的名字后附加一串

2) 局部临时表(以“#”开头命名的)作用域仅仅在当前的连接内,从在存储过程中建立局部临时表的角度来看,局部临时表会在下列情况被Drop:

a.显式调用DROP Table语句

b.当局部临时表在存储过程内被创建时,存储过程结束也就意味着局部临时表被DROP

c.当前会话结束,在会话内创建的所有局部临时表都会被Drop

3) 全局临时表(以“##”开头命名的)在所有的会话内可见,所以在创建全局临时表之前首先检查其是否存在,否则如果已经存在,你将会得到重复创建对象的错误.

a.全局临时表会在创建其的会话结束后被DROP,其它会话将不能对全局临时表进行引用。

b.引用是在语句级别进行,比如说下面例子:

i.建立新的查询窗口,运行如下语句:

     create table ##temp (RowID int)

ii.再次开启一个新的查询创建,使用如下语句每5秒中对全局临时表进行引用

     while 1=1 beginselect * from ##tempwaitfor delay '00:00:05'end

iii.回到第一个窗口,关闭窗口

iv.在下一个循环引用全局临时表时,将产生错误

4) 不能对临时表进行分区。

5) 不能对临时表加外键约束

6) 临时表内列的数据类型不能定义成没有在TempDb中没有定义自定义数据类型(自定义数据类型是数据库级别的对象,而临时表属于TempDb),由于TempDb在每次SQL Server重启后会被自动创建,所以你必须使用startup stored procedure来为TempDb创建自定义数据类型。你也可以通过修改Model数据库来达到这一目标。

7) XML列不能定义成XML集合的形式,除非这个集合已经在TempDb中定义

临时表既可以通过Create Table语句创建,也可以通过”SELECT <select_list> INTO #table”语句创建。你还可以针对临时表使用”INSERT INTO #table EXEC stored_procedure”这样的语句。

临时表可以拥有命名的约束和索引。但是,当两个用户在同一时间调用同一存储过程时,将会产生”There is already an object named ‘<objectname>’ in the database”这样的错误。所以最好的做法是不用为建立的对象进行命名,而使用系统分配的在TempDb中唯一的。6

参考6谈论了很多由于临时表而导致的存储过程重编译的原因以及避免的方法。

误区

误区1.表变量仅仅在内存中。

误区2.临时表仅仅存储在物理介质中

这两种观点都是明显的误区,在参考1的Q4节。表变量都是在TempDb数据库中创建,因为表变量存储的数据有可能超过物理内存。除此之外,我们发现只要内存足够,表变量和临时表都会在内存中创建和处理。它们也同样可以在任何时间被存入磁盘。

如何证明这点?请看下面代码(在SQL Server 2000到2008中都有效)

-- make a list of all of the user tables currently active in the
 -- TempDB database
 if object_id('tempdb..#tempTables') is not null drop table #tempTables
 select name into #tempTables from tempdb..sysobjects where type ='U'
 -- prove that even this new temporary table is in the list.
 -- Note the suffix at the end of it to uniquely identify the table across sessions.
 select * from #tempTables where name like '#tempTables%'
 GO
 -- create a table variable
 declare @MyTableVariable table (RowID int)
 -- show all of the new user tables in the TempDB database.
 select name from tempdb..sysobjects
  where type ='U' and name not in (select name from #tempTables)

还有一些“证明”临时表仅仅存在于内存中谬误,下面我来指出其中一个:

注意表变量的名字是系统分配的,表变量的第一个字符”@”并不是一个字母,所以它并不是一个有效的变量名。系统会在TempDb中为表变量创建一个系统分配的名称,所以任何在sysobjects或sys.tables查找表变量的方法都会失败。

正确的方法应该是我前面例子中的方法,我看到很多人使用如下查询查表变量:

 select * from sysobjects where name like'#tempTables%'

上述代码看上去貌似很好用,但会产生多用户的问题。你建立两个连接,在第一个连接中创建临时表,在第二个窗口中运行上面的语句能看到第一个连接创建的临时表,如果你在第二个连接中尝试操作这个临时表,那么可能会产生错误,因为这个临时表不属于你的会话。

误区3.表变量不能拥有索引。

这个误区也同样错误。虽然一旦你创建一个表变量之后,就不能对其进行DDL语句了,这包括Create Index语句。然而你可以在表变量定义的时候为其创建索引)比如如下语句.

declare @MyTableVariable table (RowID intPRIMARY KEY CLUSTERED) 

这个语句将会创建一个拥有聚集索引的表变量。由于主键有了对应的聚集索引,所以一个系统命名的索引将会被创建在RowID列上。

下面的例子演示你可以在一个表变量的列上创建唯一约束以及如何建立符合索引。

 declare @temp TABLE (RowID int NOT NULL,ColA int NOT NULL,ColB char(1)UNIQUE,PRIMARY KEY CLUSTERED(RowID, ColA))

1) SQL 并不能为表变量建立统计信息,就像其能为临时表建立统计信息一样。这意味着对于表变量,执行引擎认为其只有1行,这也意味着针对表变量的执行计划并不是最优。虽然估计的执行计划对于表变量和临时表都为1,但是实际的执行计划对于临时表会根据每次存储过程的重编译而改变(看参考1,Q2部分).如果临时表不存在,在生成执行计划的时候会产生错误。

2) 前面提到,一定建立表变量后就无法对其进行DDL语句操作。因此如果需要为表建立索引或者加一列,你需要临时表。

3) 表变量不能使用select …into语句,而临时表可以

4) 在SQL Server 2008中,你可以将表变量作为参数传入存储过程。但是临时表不行。在SQL Server 2000和2005中表变量也不行。

5) 作用域:表变量仅仅在当前的批处理中有效,并且对任何在其中嵌套的存储过程等不可见。局部临时表只在当前会话中有效,这也包括嵌套的存储过程。但对父存储过程不可见。全局临时表可以在任何会话中可见,但是会随着创建其的会话终止而DROP,其它会话这时就不能再引用全局临时表。

6) 排序规则:表变量使用当前数据库的排序规则,临时表使用TempDb的排序规则。如果它们不兼容,你还需要在查询或者表定义中进行指定(参考7.Table Variables and Temporary Tables)

7) 你如果希望在动态SQL中使用表变量,你必须在动态SQL中定义表变量。而临时表可以提前定义,在动态SQL中进行引用。

说了这么多,那么,我该如何选择呢?

微软推荐使用表变量(看参考4),如果表中的行数非常小,则使用表变量。很多”网络专家”会告诉你100是一个分界线,因为这是统计信息创建查询计划效率高低的开始。但是我还是希望告诉你针对你的特定需求对临时表和表变量进行测试。很多人在自定义函数中使用表变量,如果你需要在表变量中使用主键和唯一索引,你会发现包含数千行的表变量也依然性能卓越。但如果你需要将表变量和其它表进行join,你会发现由于不精准的执行计划,性能往往会非常差。

为了证明这点,请看本文的附件。附件中代码创建了表变量和临时表.并装入了AdventureWorks数据库的Sales.SalesOrderDetail表。为了得到足够的测试数据,我将这个表中的数据插入了10遍。然后以ModifiedDate 列作为条件将临时表和表变量与原始的Sales.SalesOrderDetail表进行了Join操作,从统计信息来看IO差别显著。从时间来看表变量做join花了50多秒,而临时表仅仅花了8秒。

如果你需要在表建立后对表进行DLL操作,那么选择临时表吧。

临时表和表变量有很多类似的地方。所以有时候并没有具体的细则规定如何选择哪一个。对任何特定的情况,你都需要考虑其各自优缺点并做一些性能测试。下面的表格会让你比较其优略有了更详细的参考。

总结

特性表变量临时表
作用域当前批处理当前会话,嵌套存储过程,全局:所有会话
使用场景自定义函数,存储过程,批处理自定义函数,存储过程,批处理
创建方式DECLARE statement only.只能通过DECLEARE语句创建

CREATE TABLE 语句

SELECT INTO 语句.

表名长度最多128字节最多116字节
列类型

可以使用自定义数据类型

可以使用XML集合

自定义数据类型和XML集合必须在TempDb内定义
Collation字符串排序规则继承自当前数据库字符串排序规则继承自TempDb数据库
索引索引必须在表定义时建立索引可以在表创建后建立
约束PRIMARY KEY, UNIQUE, NULL, CHECK约束可以使用,但必须在表建立时声明PRIMARY KEY, UNIQUE, NULL, CHECK. 约束可以使用,可以在任何时后添加,但不能有外键约束
表建立后使用DDL (索引,列)不允许允许.
数据插入方式INSERT 语句 (SQL 2000: 不能使用INSERT/EXEC).

INSERT 语句, 包括 INSERT/EXEC.

SELECT INTO 语句.

Insert explicit values into identity columns (SET IDENTITY_INSERT).不支持SET IDENTITY_INSERT语句支持SET IDENTITY_INSERT语句
Truncate table不允许允许
析构方式批处理结束后自动析构显式调用 DROP TABLE 语句. 
当前会话结束自动析构 (全局临时表: 还包括当其它会话语句不在引用表.)
事务只会在更新表的时候有事务,持续时间比临时表短正常的事务长度,比表变量长
存储过程重编译会导致重编译
回滚不会被回滚影响会被回滚影响
统计数据不创建统计数据,所以所有的估计行数都为1,所以生成执行计划会不精准创建统计数据,通过实际的行数生成执行计划。
作为参数传入存储过程仅仅在SQL Server2008, 并且必须预定义 user-defined table type.不允许
显式命名对象 (索引, 约束).不允许允许,但是要注意多用户的问题
动态SQL必须在动态SQL中定义表变量可以在调用动态SQL之前定义临时表

参考:

1) INF: Frequently Asked Questions - SQL Server 2000 - Table Variables

2) T-SQL BOL (SQL 2000), table data type

3) T-SQL BOL (SQL 2008), Declare @local_variable

4) T-SQL BOL (SQL 2008), CREATE TABLE

5) Table-Valued Parameters (Database Engine)

6) Troubleshooting stored procedure recompilation

7) Local Temporary Tables and Table Variables

8) Startup stored procedure

9) Data Definition Language (DDL)

其它值得阅读的文章:

1) Things You Didn’t Know About Temp Tables and Table Variables

-----------------------------------------------------------------------

原文链接:http://www.sqlservercentral.com/articles/Temporary+Tables/66720/

Translated by:CareySon

相关文章:

grub加密。

一、介绍 安全无小事 linux系统的安全分为很多方面&#xff0c;什么端口啊&#xff0c;什么网络啊&#xff0c;听着都特么烦&#xff0c;今天谈谈最简单明显的密码安全。 二、单用户模式 单用户模式个人觉得相当有用&#xff0c;可以用来修复系统&#xff0c;修改密码…… 但是…

Linux下stat + 文件名后, Access,Modify,Change的含义

我们首先在一个目录下创建了一个文件使用命令touch file然后输入命令&#xff1a;stat file&#xff0c;这个时候会输出一系列信息大家注意红色框中的三个时间Access : 文件最近一次被访问的时间Modify: 文件内容最近一次被修改的时间Change: 文件属性最近一次被改变的时间接着…

基于设计模式的学习之旅-----访问者模式(附源码)

基于设计模式的学习之旅-----访问者模式 1、初始访问者模式 2、什么是访问者模式 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 3、模式结构图 4、模式代码事例 场景&#xff1a;年会&#xff0c;每个小组表演…

x is y python_Python 基础

2.1 程序与用户交互在python3中#input&#xff1a;无论用输入何种类型&#xff0c;都会存成字符串类型nameinput(please input your name:) #name18print(id(name),type(name),name)在python2中#raw_input与python3的input是一样的nameraw_input(please input your name:)print…

【leetcode 简单】 第八十九题 赎金信

给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串&#xff0c;判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成。如果可以构成&#xff0c;返回 true &#xff1b;否则返回 false。 (题目说明&#xff1a;为了不暴露赎金信字迹&#xff0c;要从杂…

创建专属博客栏目

今天给大家get新技能了&#xff0c;是不是很期待捏我们一般看到的博客页面是这样的但是你是不是特别期待这样的捏其实技术上面也不是特别的 难&#xff0c;我们登录自己的csdn博客&#xff0c;然后选择“管理博客”&#xff0c;跳转页面之后选择“博客栏目”进入到这个页面之后…

《帝企鹅日记》观后感

第一次看到是在高中的英语周报上&#xff0c;那时候蛮好奇的&#xff0c;企鹅也写日记&#xff0c;呵呵&#xff0c;后来想了想应该是纪录片&#xff0c;时隔三年&#xff0c;发现当初的猜测果然不假。 我觉得那些企鹅很可爱&#xff0c;也很漂亮。最重要的是&#xff0c;那一条…

合并道路_资质改革已经确定!盘点被合并的资质!有这资质的要注意了

资质改革可以说是在行业里掀起了轩然大波&#xff0c;众多资质面临改革&#xff0c;有的资质被取消&#xff0c;有的资质被合并&#xff0c;有的资质继续保留。此文就带大家来盘点一下那些在近期资质定稿中被取消&#xff0c;被改变的资质&#xff1a;勘察资质勘察资质中&#…

如何为ccflow工作流引擎增加一个优先级PRI?

为什么80%的码农都做不了架构师&#xff1f;>>> 如何为ccflow工作流引擎增加一个优先级PRI&#xff1f; 对于一条流程的优先级可分为 低&#xff0c;中&#xff0c;高三个级别&#xff0c;用这个状态来标示这条流程的紧急程度。 以以前版本的ccflow中是以节点表…

SQL Server (MSSQLSERVER) 服务因 2148081668 服务性错误而停止。

https://zhidao.baidu.com/question/151448005.html 具体步骤&#xff1a;运行-> 输入&#xff1a;“services.msc” ->找到 “SQL Server (SQLEXPRESS)” 服务&#xff0c;双击 -> 在“SQL Server (SQLEXPRESS) 的属性”界面&#xff0c;点登录 -> 默认登录身份是…

面试题--特别是字节对齐

来源&#xff1a;http://www.cnblogs.com/Braveliu/archive/2013/01/04/2844757.html 【1】设置或者清除某位。 示例代码如下: 1 #include<iostream>2 using namespace std;3 4 #define BIT3 (0x1<<3)5 6 void Set_bit3(int &a)7 {8 a|BIT3;9 } 10 11…

vim基础入门

一. vim的三种模式在Linux操作系统下&#xff0c;我们一般会使用vim进行文本编辑&#xff0c;它相当于Windows下的记事本&#xff0c;但是它比记事本的功能强大的多。vim一般有三种模式分别是普通模式&#xff0c;编辑模式和命令模式。普通模式和编辑模式可以来回的切换&#x…

python html解析查找字符串_用python的BeautifulSoup分析html

序言之前用python爬取网页的时候&#xff0c;一直用的是regex或者自带的库sgmllib里的SGMLParser。但是遇到复杂一点的情况时&#xff0c;SGMLParser往往就不那么给力了&#xff01;(哈&#xff0c;难道说我 too native了&#xff1f;毕竟beautifulSoup是继承sgmlparser的么~)所…

ejb 3中bean的种类

会话bean(session bean) 主要用来编写业务逻辑和对数据库进行操作&#xff0c;Session Bean用于实现业务逻辑&#xff0c;它分为有状态bean和无状态bean。每当客户端请求时&#xff0c;容器就会选择一个Session Bean来为客户端服务。Session Bean可以直接访问数据库&#xff0…

Android学习 —— 数据的存储与访问方式一: 文件存取

笔记摘要&#xff1a; 在Android中主要提供了四种数据存储与访问的方式&#xff0c;文件、SharedPreference&#xff08;偏好参数保存&#xff09;、SOLite数据库、内容提供者&#xff08;Content provider&#xff09;和网络&#xff0c; 本篇文章先介绍使用文件的方式进行数据…

react的安装使用

react的重要思想是通过组件来开发应用&#xff0c;而组件就是能够完成某个特定功能而独立、可复用的代码。 react是可以像JQuery那样直接下载引入使用&#xff0c;也可以直接引用官网提供的CDN的地址&#xff1a; <script src"https://unpkg.com/react16/umd/react.dev…

锐捷交换机配置snmp版本_snmp交换机配置

华为交换机1、查询交换机当前是snmp配置命令dis cur2、进入全局模式 int ethernet1/0/7 shutdown 关 undoshutdown 激活sys3、进入SNMP配置snmp-agent4、配置只读字符串snmp-agent community read abcd5、配置写字符串snmp-agent community write abcd6、开启snmp版本支持功能 …

Linux命令find的35个实例

注&#xff1a;本文内容参考《35 Practical Examples of Linux Find Command》 网址&#xff1a;http://www.tecmint.com/35-practical-examples-of-linux-find-command/ Linux 查找命令是Linux系统中最重要和最常用的命令之一。查找用于根据与参数匹配的文件指定的条件来搜索…

PHP使用APNS的 feedback service

http://blog.csdn.net/gnicky/article/details/7544202 1. URL是不一样的&#xff0c;端口是2196 2. 使用同样的Certificate&#xff0c;建立安全连接&#xff0c;接受数据&#xff0c;直到数据不存在&#xff0c;类似table select操作 3.每条纪录是一个token&#xff0c;serve…

洛谷——P2341 [HAOI2006]受欢迎的牛//POJ2186:Popular Cows

P2341 [HAOI2006]受欢迎的牛/POJ2186:Popular Cows 题目背景 本题测试数据已修复。 题目描述 每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶 牛都是自恋狂&#xff0c;每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜 欢…

学习使用Bing Maps Silverlight Control(五):离线使用和自定义地图模式

6 离线使用 在笔记第一部分的时候就提到如果要使用Bing Maps Silverlight Control 进行开发&#xff0c;需要申请一个key&#xff0c;不让会显示一个错误提示出来。但是在实际开发或使用过程中&#xff0c;使用环境和地图数据可能不是在线的&#xff0c;但控件因为验证失败仍然…

python123第k序元素查找_Python实现折半查找并用matplotlib实现动态过程可视化

折半查找是算法中减治策略的基本例子&#xff0c;实现起来也很简单&#xff0c;但是在网上看到的图片教程不觉得很乾巴麽&#xff1f;&#xff1f;在这里插入图片描述这是一个简单的实现&#xff1a;def Reduction(lists, k):""":param lists: 元素列表:param k…

vim进阶技巧

本篇博文是在之前的《vim基础入门》的基础之上写的&#xff0c;不懂的同学可以先看之前的分享 1. 视觉范围的选择 普通模式下&#xff0c;按v键确定范围起点&#xff0c;然后移动光标&#xff0c;光标所在位置为范围的终点&#xff0c;然后按操作键完成其他操作&#xff0c;之…

Flex Air程序打包成独立的exe安装文件

2019独角兽企业重金招聘Python工程师标准>>> 开发背景&#xff1a; FlexBuilder3.2开发生成的Air程序需要能够独立安装&#xff0c;事先不需要安装AdobeAir运行环境 实现方法&#xff1a; 1)用winrar打开xx.air文件爱能&#xff0c;并将它解压在D:\airapp目录中。 2…

《C++primer》第一章--开始

之前开始读《Cprimer》&#xff0c;想着读书不动笔不如不读书&#xff0c;于是就想做一个读书笔记的内容&#xff0c;于是就想起了写一个《Cprimer读思录》的一个专栏。一是为了给自己平时读书做笔记&#xff0c;方便自己随时查看。二是为了督促自己每天学习。三是为了知识的分…

对于计算机网络的整体框架的概括(转载) 个人感觉很好

作者&#xff1a; 阮一峰 日期&#xff1a; 2012年5月31日 我们每天使用互联网&#xff0c;你是否想过&#xff0c;它是如何实现的&#xff1f; 全世界几十亿台电脑&#xff0c;连接在一起&#xff0c;两两通信。上海的某一块网卡送出信号&#xff0c;洛杉矶的另一块网卡居然就…

Centos修改系统语言

使用man page帮助时&#xff0c;发现居然是中文的&#xff0c;不过想想即便英语再水&#xff0c;也要逼着自己去适应。于是百度找了一下修改系统语言的方法。 首先使用 locale 命令查看当前的系统语言 然后修改时一般有两种方法&#xff0c;一是临时修改&#xff0c;立即生效&a…

tp3 普通模式url模式_Thinkphp 3.2.3 url 路由访问模式

Thinkphp 3.2.3 url 的4中路由模式&#xff1a;// 0 (普通模式)http://网址/index.php?m模块&c控制器&a方法http://localhost/index.php?mHome&cindex&aindex//1 (PATHINFO 模式) 默认为PATHINFO 模式http://网址/index.php/模块/控制器/方法http://localhos…

Mysql 基于 Amoeba 的 读写分离(2)

<?xml version"1.0" encoding"gbk"?> <!DOCTYPE amoeba:configuration SYSTEM "amoeba.dtd"> <amoeba:configuration xmlns:amoeba"http://amoeba.meidusa.com/"><proxy><!-- service class must implem…

Linux驱动之LCD驱动编写

在Linux驱动之内核自带的S3C2440的LCD驱动分析这篇博客中已经分析了编写LCD驱动的步骤&#xff0c;接下来就按照这个步骤来字尝试字节编写LCD驱动。用的LCD屏幕为tft屏&#xff0c;每个像素点为16bit。对应与红绿蓝分别为565。 1、分配一个fb_info结构 2、设置fb_info结构 3、硬…