原文:TempDB 中表变量和局部临时表的对比

参考资料来源:

http://blogs.msdn.com/b/sqlserverstorageengine/archive/tags/tempdb/

http://blogs.msdn.com/b/sqlserverstorageengine/archive/2008/03/30/sql-server-table-variable-vs-local-temporary-table.aspx

我们都知道,tempdb是用来为应用程序和SQL Server临时储存运行的中间结果的。由用户和应用程序创建的对象叫做用户对象,由SQL

Server引擎产生的对象叫做内部对象,在这篇博文中,我们主要讨论用户对象中的临时表(#,##)和表变量。大家可能对##表(全局临时表)和#表(局部临时表)的区别比较了解,但对临时表和表变量却不是很清楚,下面我们详述两者的主要区别。

和其他变量一样,表变量是一种非常有用的程序构造。表变量的有效范围和其他程序变量的有效范围是一样的。例如,如果你在存储过程中定义了一个变量,那么它就不能在存储过程外被访问。巧合的是,临时表也是这样的。那为什么我们还要创建表变量呢?因为表变量在存储过程中可以作为输出/输入参数(此功能从SQL

Server2008开始可用)或者用来存储函数的返回结果。以下是表变量和临时表的相同和不同之处:

•       首先,表变量不一定常驻内存。在内存压力大的时候,属于表变量的页可以被放入tempdb。以下是一个例子描述表变量在tempdb中所占空间。

use tempdb

go

drop table #tv_source

go

create table #tv_source(c1 int, c2 char(8000))

go

declare @i int

select @i = 0

while (@i < 1000)

begin

insert into #tv_source values (@i, replicate ('a', 100))

select @i = @i + 1

end

DECLARE @tv_target TABLE (c11 int, c22 char(8000))

INSERT INTO @tv_target (c11, c22)

SELECT c1, c2

FROM  #tv_source

-- checking the size through DMV.

-- The sizes here are in 8k pages. This shows the

allocated space

-- to user objects to be 2000 pages (1000 pages

for #tv_source and

-- 1000 pages for @tv_target

Select total_size = SUM (unallocated_extent_page_count) +

SUM (user_object_reserved_page_count) +

SUM (internal_object_reserved_page_count) +

SUM (version_store_reserved_page_count) +

SUM (mixed_extent_page_count),

SUM (unallocated_extent_page_count) as freespace_pgs,

SUM (user_object_reserved_page_count) as user_obj_pgs,

SUM (internal_object_reserved_page_count) as internal_obj_pgs,

SUM (version_store_reserved_page_count)  as version_store_pgs,

SUM (mixed_extent_page_count) as mixed_extent_pgs

from sys.dm_db_file_space_usage

•         其次,如果您创建了一个表变量,它会像一个常规的DDL操作一样将元数据储存在系统目录中,以下示例说明了这一点:

declare @ttt TABLE(c111 int, c222 int)

select name from sys.columns where object_id > 100 and name

like 'c%'

结果会返回两行,包含列C111和C222。这表明如果遇到定义冲突时,把临时表改成表变量不能解决问题。

•         第三,事务处理和锁定语句。表变量不能参与事务处理和锁定,以下示例说明了这一点

-- create a source table

create table

tv_source(c1 int, c2 char(100))

go

declare @i int

select @i = 0

while (@i < 100)

begin

insert into tv_source values (@i, replicate ('a', 100))

select @i = @i + 1

end

-- using #table

create table #tv_target (c11 int, c22 char(100))

go

BEGIN TRAN

INSERT INTO #tv_target (c11, c22)

SELECT c1, c2

FROM 

tv_source

--

using table variable

DECLARE @tv_target TABLE (c11 int, c22 char(100))

BEGIN TRAN

INSERT INTO @tv_target (c11, c22)

SELECT c1, c2

FROM  tv_source

-- Now if I look at the locks, you will see that

only

-- #table takes locks. Here is the query that

used

-- to check the locks

select

t1.request_session_id as spid,

t1.resource_type as type,

t1.resource_database_id as dbid,

(case

resource_type

WHEN 'OBJECT' then object_name(t1.resource_associated_entity_id)

WHEN 'DATABASE' then ' '

ELSE (select object_name(object_id)

from sys.partitions

where hobt_id=resource_associated_entity_id)

END) as objname,

t1.resource_description as description,

t1.request_mode as mode,

t1.request_status as status,

t2.blocking_session_id

from sys.dm_tran_locks as t1 left outer join sys.dm_os_waiting_tasks as t2

ON t1.lock_owner_address = t2.resource_address

另一个有趣的现象是,如果回滚的事务里涉及表变量,表变量的数据不会被回滚。

Rollback

-- this

query will return 100 for table variable but 0 for #table.

SELECT COUNT(*) FROM @tv_target

•         第四,表变量上的操作不被日志文件记录。请看下面这个例子:

--

create a table variable, insert bunch of rows and update

DECLARE @tv_target TABLE (c11 int, c22 char(100))

INSERT INTO @tv_target (c11, c22)

SELECT c1, c2

FROM  tv_source

-- update all the rows

update @tv_target set c22 = replicate ('b', 100)

-- look at the top 10 log records. I get no

records for this case

select top 10 operation,context, [log record fixed length], [log record length],

AllocUnitId, AllocUnitName

from fn_dblog(null, null)

where AllocUnitName like '%tv_target%'

order by [Log Record Length] Desc

-- create a local temptable

drop table #tv_target

go

create table #tv_target (c11 int, c22 char(100))

go

INSERT INTO #tv_target (c11, c22)

SELECT c1, c2

FROM  tv_source

--

update all the rows

update #tv_target set c22 = replicate ('b', 100)

-- look

at the log records. Here I get 100 log records for update

select 

operation,context, [log

record fixed length], [log record length], AllocUnitName

from fn_dblog(null, null)

where AllocUnitName like '%tv_target%'

order by [Log

Record Length] Desc

•         第五,表变量中不允许DDL运行,所以,如果你有一个大的行集需要经常进行查询,您可能要使用临时表并创建合适的索引。你可以在声明表变量时创建唯一约束来解决这个问题。

•         第六,表变量不维护统计数据。这意味着任何表变量数据更改都不会引起相关查询语句进行重编译。

•         最后, 涉及表变量的查询不能生成并行的查询计划,因此我们认为对于庞大的临时数据集最好使用临时表来发挥并行查询的优势。

TempDB 中表变量和局部临时表的对比的更多相关文章

  1. sqlserver中表变量和变量表之间区别

    sqlserver中表变量和变量表之间区别

  2. Python决定一个变量时局部的,还是全局的,是在编译期

    Python中的变量名是在编译时就解析好的,换句话说,在编译时(也就是在交互控制台输入代码是或者import文件时),Python就已经决定一个变量应该是局部变量,还是全局变量.来看下面的例子: &g ...

  3. vs如何新建自己工程的环境变量(局部)和 Windows系统(全局).

    来源:http://blog.csdn.net/jtop0/article/details/7574139        在vs2008的Project->Property设置里经常会看到类似$ ...

  4. Sqlserver 实际开发中表变量的用法

    在实际的开发中,我们可能遇到的问题是,在一个存储过程里面,我们可能要返回多段sql的结果集,但是最终怎么把多个结果集合成一块呢,那么这个时候临时表变量就来了 declare  @tmp table   ...

  5. vs2008如何新建自己工程的环境变量(局部)和 Windows系统(全局). .

    在vs2008的Project->Property设置里经常会看到类似$(IntDir).$(OutDir).$(ProjectName) 的预定义宏.以vc2008为例,有时候我们在引用别的库 ...

  6. sql中表变量

    今天在公司看sql优化的文章的时候,提到了表变量,做下笔记. 表变量 顺便复习下临时表.

  7. (八)Activiti之流程变量和局部流程变量

    一.流程变量 1.1 概念 如果,当流程走到"学生请假"这个任务节点的时候,此时可以用TaskService设置流程变量,变量值包含请假人.请假时间.请假理由等信息,这些信息存在表 ...

  8. 在SSIS中的不同组件间使用局部临时表

    Connetion的属性RetainSameConnection是个boolean值,指定是否保持相同的链接,默认值是false,表示每个component都会单独的使用connection,在com ...

  9. java静态变量、实例变量和局部变

    实例变量又称成员变量: 1⃣️成员变量定义在类中,在整个类中都可以被访问 2⃣️成员变量随着对象的建立而建立,随对象的消失而消失,存在于对象所在的对内存中 3⃣️成员变量有默认初始值 局部变量: 1⃣ ...

随机推荐

  1. POJ2239_Selecting Courses(二分图最大匹配)

    解题报告 http://blog.csdn.net/juncoder/article/details/38154699 题目传送门 题意: 每天有12节课.一周上7天,一门课在一周有多天上课. 求一周 ...

  2. 解决tomcat开始出现in production environments was not found on the java.library.path:xxx

    如图所看到的,Eclipse中启动tomcat时出现not found on the java.library.path等信息.能够通过下载tomcat-native-1.1.32-win32-bin ...

  3. JavaEEB2C网上商城前端系统

    问题的提出: 电子商务已经成为人们生活中不可或缺的组成部分,它提供了一种足不出户就可以挑选.购买.使用商品的方式.在众多点上网站中,综合类的B2C电商以其较高的可信度,丰富的商品类目,得到消费者的青睐 ...

  4. Linux如何用QQ?Linux下QQ使用的几种方案

    在linux下如何使用QQ?在ubuntu11.10中如何使用QQ?或许有初涉linux的人这样问,我们可以看看ubuntusoft总结出来的几种在linux系统下用QQ的方法.前面的几种主要的方法都 ...

  5. 《实验数据的结构化程序设计》 2.4.4Calendar个人意见,寻求指引

    题目大意: 制作一个日历系统,输入年份.一些周年纪念日,及服务要求日期,依据要求日期输出,输出重要程度小于发生日期的周年纪念日. 题目地址: UVA  145 个人见解: 纯模拟,在闰年,输出顺序及输 ...

  6. CentOS 安装memcached

    一,安装libevent 安装位置 /usr/lib #tar -zxvf libevent-2.0.21-stable.tar.gz # cdlibevent-2.0.21 # ./configur ...

  7. 在汉澳sinox2014建立ZFS高可靠文件存储系统

    在汉澳sinox2014建立ZFS高可靠文件存储系统 汉澳sinox2014能够用比較小的固态硬盘安装,文件系统能够用zfs系统存放. 请准备一些硬盘,比方三块SCSI硬盘:da0,da1,da2 如 ...

  8. iOS8数字键盘加左下角完成button

    iOS8数字键盘加左下角完成button的核心代码如下面: - (void)addDoneButtonToNumPadKeyboard { UIButton *doneButton = [UIButt ...

  9. 人人API 分享到人人功能 修改版

    最近在搞一个日程管理网站, 需要实现分享到人人功能, 所以找了一下人人API, 然后根据自己需要修改了一下. 首先得有一个人人给的js文件, 如下: var Renren = Renren || {} ...

  10. TinyXml高速入口(一)

    笔者:朱金灿 来源:http://blog.csdn.net/clever101 对于xml文件,眼下我的工作仅仅是集中在配置文件和作为简单的信息文件来用.因此我不太喜欢使用msxml这样的重量级的x ...