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

原文: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运行,所以,如果你有一个大的行集需要经常进行查询,您可能要使用临时表并创建合适的索引。你可以在声明表变量时创建唯一约束来解决这个问题。

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

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

时间: 2024-11-08 19:26:17

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

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

在vs2008的Project->Property设置里经常会看到类似$(IntDir).$(OutDir).$(ProjectName) 的预定义宏.以vc2008为例,有时候我们在引用别的库时需要在项目设置里添加额外的头文件和库文件路径,我们不想每个路径都用一大堆的"../.. /include"或绝对路径表示,因为不但繁琐而且万一路径改变每处都要修改,不方便维护,我们希望能自定义类是$(myDir) = c:/myPrj/include的宏.有人说: "vcpro

JAVASCRIPT变量之局部/全局变量

局部 JavaScript 变量 在 JavaScript 函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它.(该变量的作用域是局部的). 您可以在不同的函数中使用名称相同的局部变量,因为只有声明过该变量的函数才能识别出该变量. 只要函数运行完毕,本地变量就会被删除. 全局 JavaScript 变量 在函数外声明的变量是全局变量,网页上的所有脚本和函数都能访问它. JavaScript 变量的生存期 JavaScript 变量的生命期从它们被声明的时间开始. 局部变量会在

SQL Server 2005中Tempdb变化分析

tempdb数据库是SQL Server用于临时或者开关操作的数据库.对tempdb所做的很多优化都是在透明的情况下,让处理加速,本文就介绍tempdb对SQL Server 2005的影响以帮助大家利用这些来写出更好的.更先进的SQL Server 2005代码. SQL Server 2005版本中的所有变化可以写成一本书,事实上,已经被写成了好几本书.其中,最重要的变化不是功能上的变化:这些变化发生在用户或者管理员无法立刻感觉到的内部的行为上.这就是说,了解到它们是什么,它们在什么状况下会

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

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

SQL Server 表变量和临时表系列之概念篇

问题引入 "菜鸟啊,最近我看到阿里云开发者论坛的数据库RDS中有人在提SQL Server表变量和临时表如何选择的问题,你去深入探讨下这个问题吧,解答解答他们的疑惑吧",老鸟又开始为菜鸟找活干了. "鸟哥啊,关于表变量和临时表使用选择的问题啊,向来行业里争论不休,我比较担心我们的观点被人家拍砖啊". "鸟啊,有争论才说明这个问题有价值啊,所以我们才更应该去弄清楚,道明白啊".反正老鸟总会找到合适的理由. "那好吧,要把这个问题要刨根问底

SQL Server 表变量和临时表的区别(详细补充篇)_MsSql

一.表变量 表变量在SQL Server 2000中首次被引入.表变量的具体定义包括列定义,列名,数据类型和约束.而在表变量中可以使用的约束包括主键约束,唯一约束,NULL约束和CHECK约束(外键约束不能在表变量中使用).定义表变量的语句是和正常使用Create Table定义表语句的子集.只是表变量通过DECLARE @local_variable语句进行定义. 表变量的特征: 1.表变量拥有特定作用域(在当前批处理语句中,但不在任何当前批处理语句调用的存储过程和函数中),表变量在批处理结束

SQL Server 表变量和临时表的区别(详细补充篇)

一.表变量 表变量在SQL Server 2000中首次被引入.表变量的具体定义包括列定义,列名,数据类型和约束.而在表变量中可以使用的约束包括主键约束,唯一约束,NULL约束和CHECK约束(外键约束不能在表变量中使用).定义表变量的语句是和正常使用Create Table定义表语句的子集.只是表变量通过DECLARE @local_variable语句进行定义. 表变量的特征: 1.表变量拥有特定作用域(在当前批处理语句中,但不在任何当前批处理语句调用的存储过程和函数中),表变量在批处理结束

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

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

对比Oracle临时表和SQL Server临时表的不同点_oracle

Oracle数据库创建临时表的过程以及和SQL Server临时表的不同点的对比的相关知识是本文我们主要要介绍的内容,接下来就让我们一起来了解一下这部分内容吧,希望能够对您有所帮助. 1.简介 Oracle数据库除了可以保存永久表外,还可以建立临时表temporary tables.这些临时表用来保存一个会话SESSION的数据,或者保存在一个事务中需要的数据.当会话退出或者用户提交commit和回滚rollback事务的时候,临时表的数据自动清空,但是临时表的结构以及元数据还存储在用户的数据字