表变量在SQL Server 2000中首次被引入。表变量的具体定义包括列定义,列名,数据类型和约束。而在表变量中可使用的约束包括主键约束,惟一约束,NULL约束和CHECK约束(外键约束不能在表变量中使用)。定义表变量的语句是和正常使用Create Table定义表语句的子集。只是表变量经过DECLARE @local_variable语句进行定义。数据库
表变量的特征:网络
表变量拥有特定做用域(在当前批处理语句中,但不在任何当前批处理语句调用的存储过程和函数中),表变量在批处理结束后自动被清除。 表变量较临时表产生更少的存储过程重编译。 针对表变量的事务仅仅在更新数据时生效,因此锁和日志产生的数量会更少。 因为表变量的做用域如此之小,并且不属于数据库的持久部分,因此事务回滚不会影响表变量。
表变量能够在其做用域内像正常的表同样使用。更确切的说,表变量能够被当成正常的表或者表表达式同样在SELECT,DELETE,UPDATE,INSERT语句中使用,可是表变量不能在相似"SELECT select_list INTO table_variable"这样的语句中使用。而在SQL Server2000中,表变量也不能用于INSERT INTO table_variable EXEC stored_procedure这样的语句中。ide
表变量不能作以下事情:函数
虽然表变量是一个变量,可是其不能赋值给另外一个变量。 check约束,默认值和计算列不能引用自定义函数。 不能为约束命名。 不能Truncate表变量。 不能向标识列中插入显式值(也就是说表变量不支持SET IDENTITY_INSERT ON)
在深刻临时表以前,咱们要了解一下会话(Session),一个会话仅仅是一个客户端到数据引擎的链接。在SQL Server Management Studio中,每个查询窗口都会和数据库引擎创建链接。一个应用程序能够和数据库创建一个或多个链接,除此以外,应用程序还可能创建链接后一直不释放知道应用程序结束,也可能使用完释放链接须要时创建链接性能
临时表和Create Table语句建立的表有着相同的物理工程,但临时表与正常的表不一样之处有:测试
局部临时表(以"#"开头命名的)做用域仅仅在当前的链接内,从在存储过程当中创建局部临时表的角度来看,局部临时表会在下列状况下被Drop:spa
全局临时表(以"##"开头命名的)在全部的会话内可见,因此在建立全局临时表以前首先检查其是否存在,不然若是已经存在,你将会获得重复建立对象的错误日志
新建查询窗口,运行语句:
CREATE TABLE ##temp(RowID int)
INSERT INTO ##temp VALUES(3)code
再次新建一个查询窗口,每5秒引用一次全局临时表
While 1=1
BEGIN
SELECT * FROM ##temp
WAITFOR delay '00:00:05'
END对象
临时表既能够经过Create Table语句建立,也能够经过"SELECT <select_list> INTO #table"语句建立。还能够针对临时表用"INSERT INTO #table EXEC stored_procedure"这样的语句
临时表能够拥有命名的约束和索引。可是,当两个用户在同一时间调用同一存储过程时,将会产生”There is already an object named '<objectname>' in the database”这样的错误。因此最好的作法是不用为创建的对象进行命名,而使用系统分配的在TempDb中惟一的
这两种观点都是错误的,只有内存足够,表变量和临时表都会在内存中建立和处理。他们也一样能够在任什么时候间被存入磁盘。注意表变量的名字是系统分配的,表变量的第一个字符”@”并非一个字母,因此它并非一个有效的变量名。系统会在TempDb中为表变量建立一个系统分配的名称,因此任何在sysobjects或sys.tables查找表变量的方法都会失败
这个误区也一样错误。虽然一旦你建立一个表变量以后,就不能对其进行DDL语句了,这包括Create Index语句。然而你能够在表变量定义的时候为其建立索引)
declare @MyTableVariable table (RowID intPRIMARY KEY CLUSTERED)
这个语句将会建立一个拥有汇集索引的表变量。因为主键有了对应的汇集索引,因此一个系统命名的索引将会被建立在RowID列上
1) SQL 并不能为表变量创建统计信息,就像其能为临时表创建统计信息同样。这意味着对于表变量,执行引擎认为其只有1行,这也意味着针对表变量的执行计划并非最优。虽然估计的执行计划对于表变量和临时表都为1,可是实际的执行计划对于临时表会根据每次存储过程的重编译而改变。若是临时表不存在,在生成执行计划的时候会产生错误
2) 一旦创建表变量后就没法对其进行DDL语句操做。所以若是须要为表创建索引或者加一列,你须要临时表
3) 表变量不能使用select …into语句,而临时表能够
4) 在SQL Server 2008中,你能够将表变量做为参数传入存储过程。可是临时表不行。在SQL Server 2000和2005中表变量也不行
5) 做用域:表变量仅仅在当前的批处理中有效,而且对任何在其中嵌套的存储过程等不可见。局部临时表只在当前会话中有效,这也包括嵌套的存储过程。但对父存储过程不可见。全局临时表能够在任何会话中可见,可是会随着建立其的会话终止而DROP,其它会话这时就不能再引用全局临时表
6) 排序规则:表变量使用当前数据库的排序规则,临时表使用TempDb的排序规则。若是它们不兼容,你还须要在查询或者表定义中进行指定
7) 你若是但愿在动态SQL中使用表变量,你必须在动态SQL中定义表变量。而临时表能够提早定义,在动态SQL中进行引用
微软推荐使用表变量,若是表中的行数很是小,则使用表变量。不少”网络专家”会告诉你100是一个分界线,由于这是统计信息建立查询计划效率高低的开始。可是我仍是但愿告诉你针对你的特定需求对临时表和表变量进行测试。不少人在自定义函数中使用表变量,若是你须要在表变量中使用主键和惟一索引,你会发现包含数千行的表变量也依然性能卓越。但若是你须要将表变量和其它表进行join,你会发现因为不精准的执行计划,性能每每会很是差
为了证实这点,请看本文的附件。附件中代码建立了表变量和临时表.并装入了AdventureWorks数据库的Sales.SalesOrderDetail表。为了获得足够的测试数据,我将这个表中的数据插入了10遍。而后以ModifiedDate 列做为条件将临时表和表变量与原始的Sales.SalesOrderDetail表进行了Join操做,从统计信息来看IO差异显著。从时间来看表变量作join花了50多秒,而临时表仅仅花了8秒
若是你须要在表创建后对表进行DLL操做,那么选择临时表
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
---|---|---|---|---|
抽象基类 | InputStream | OutputStream | Reader | Writer |
特性 | 表变量 | 临时表 | |
---|---|---|---|
做用域 | 当前批处理 | 当前会话,嵌套存储过程,全局:全部会话 | |
使用场景 | 自定义函数,存储过程,批处理 | 自定义函数,存储过程,批处理 | |
建立方式 | 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以前定义临时表 |