原文: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. 局部临时表 全局临时表 表变量

    表变量: DECLARE @tb  table(id   int   identity(1,1), name   varchar(100))     INSERT @tb SELECT id, nam ...

  2. 【Sql Server】数据库变量表和临时表的区别,并运用变量表遍历和随机生成姓名记录

    作者:小5聊 简介:一只喜欢全栈方向的程序员,欢迎咨询,尽绵薄之力答疑解惑 公众号:有趣小馆,一个有趣的关键词回复互动功能 目录 1.表变量 1.1.表变量基本信息 1.2.表变量使用场景 1.3.表 ...

  3. STM32对SD卡数据读取和在Ubuntu、stm32下的C程序中堆、栈、全局、局部等变量的分配地址的对比分析

    一.SD卡协议原理 1.SD卡简介 SD存储卡是一种基于半导体快闪记忆器的新一代记忆设备,由于它体积小.数据传输速度快.可热插拔等优良的特性,被广泛地于便携式装置上使用,例如数码相机.平板电脑和多媒体 ...

  4. oracle 中表变量的用法,oracle 表类型变量的使用

    使用记录类型变量只能保存一行数据,这限制了SELECT语句的返回行数,如果SELECT语句返回多行就会错.Oracle提供了另外一种自定义类型,也就是表类型,它是对记录类型的扩展,允许处理多行数据,类 ...

  5. 字符指针变量和字符数组的对比

    使用字符数组和指针变量都能实现字符串的存储和运算,但它们两者之间是有区别的,不应混为一谈,主要有一下几点: (1)字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串中 ...

  6. 11种离散型变量编码方式及效果对比

    首先介绍一个关于离散型编码的Python库,里面封装了十几种(包括文中的所有方法)对于离散型特征的编码方法,接口接近于Sklearn通用接口,非常实用.下面是这个库的链接:Category Encod ...

  7. 查询表授权给谁了_SQL Server 全局临时表竞争条件漏洞利用

    在网络和应用程序渗透测试期间,SQL Server 全局临时表通常不是关注的焦点.然而,它们被开发人员周期性地不安全地用来存储敏感数据和代码块,这些数据和代码块可以被非特权用户访问.在本博客中,我将介 ...

  8. 第八章 了解tempdb数据库

    1.一个sqlserver数据库实例上只能有一个tempdb数据库,这个实例上所有的用户都共享这个数据库. 2.tempdb数据库在每次sqlserver重启后都会重新创建,所以数据会丢失. 3.因为 ...

  9. T-SQL 之 表变量和临时表

    一.表变量 表变量在SQL Server 2000中首次被引入.表变量的具体定义包括列定义,列名,数据类型和约束.而在表变量中可以使用的约束包括主键约束,唯一约束,NULL约束和CHECK约束(外键约 ...

最新文章

  1. 《Java虚拟机原理图解》5. JVM类加载器机制与类加载过程
  2. 远程桌面中Tab键不能补全的解决办法
  3. 第一篇:数据库基本管理(mysql)
  4. SAP 限制出货数量小于销售订单数量
  5. boost::geometry::svg用法的测试程序
  6. 手机是如何实现自动对焦的?
  7. 前端学习(2002)vue之电商管理系统电商系统之绘制商品分类的级联选择器
  8. Qt4_读取和写入文本
  9. php complex,PHP復雜的基於角色的訪問控制列表
  10. RHCE-PXE无人值守装机一
  11. cordova与android通信_使用Cordova插件实现两个app之间的相互调用和通讯
  12. 树莓派控制超声波测距原理及实现
  13. 小技巧 - 淘宝怎么联系人工客服?
  14. 【进阶】QQ聊天机器人--群聊机器人篇
  15. 心灵捕手——走进内心世界
  16. 扫盲:集线器、网桥、交换机、路由器、网关大解析
  17. ArcGISPro制作辐射4风格地图
  18. 20、随机图片验证码API接口,免费好用
  19. 华为ensp基础实验(一)
  20. 宝塔面板下载网站日志,分析百度蜘蛛和谷歌蜘蛛的爬取记录

热门文章

  1. 零基础 | 入行软件测试,你想知道的都在这里了
  2. 辞职腾讯去了小公司,从0到1搭建后端架构,工资就翻倍了
  3. 免装版_一款好用的便签工具 桌面便签免安装版
  4. 7z替换exe文件内容不能替换文件_Windows小技巧 批处理文件实现目录下文件批量打包压缩...
  5. java类对象转化成字符串_String类型字符串(xml格式)转换成java对象类型
  6. add script param in pycharm
  7. 18复变函数的积分(四)
  8. Numpy的使用(2)
  9. oracle多表嵌套查询使用,oracle sql 多表 嵌套子查询 连接查询, join where exist i...
  10. tomcat上的javaweb项目如何将ip地址更换为域名_Java Web 路线规划