`
sjk2013
  • 浏览: 2177587 次
文章分类
社区版块
存档分类
最新评论

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

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

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

    分享到:
    评论

    相关推荐

      SQLServer中临时表与表变量的区别分析

      在实际使用的时候,我们如何灵活的在存储过程中运用它们,虽然它们实现的功能基本上是一样的,可如何在一个存储过程中有时候去使用临时表而不使用表变量,有时候去使用表变量而不使用临时表呢? 临时表  临时表与...

      sql server 临时表详解与示例

      1、局部临时表(#开头)只对当前连接有效,当前连接断开时自动删除。 2、全局临时表(##开头)对...临时表有两种,局部的和全局的.和普通表的表面上的区别就是 分别以#和##开头.她们是保存在磁盘上的tempdb数据库里的

      存储过程中的临时表使用方法

      创建临时表。临时表与永久表相似,但临时表存储在 tempdb 中,当不再使用时会自动删除。

      Sql Server临时表和游标的使用小结

      实际上局部临时表在tempdb中是有唯一名称的 例如我们用sa登陆一个查询分析器,再用sa登陆另一查询分析器 在2个查询分析器我们都允许下面的语句: use pubs go select * into #tem from jobs 分别为2个用户

      临时表操作详解SQL Server 实例

      临时表与永久表相似,但临时表存储在 tempdb 中,当不再使用时会自动删除。 临时表有两种类型:本地和全局。它们在名称、可见性以 及可用性上有区别。本地临时表的名称以单个数字符号 (#) 打头;它们仅对当前的用户...

      SqlServer数据库提示 “tempdb” 的日志已满 问题解决方案

      执行sql 语句,中间没有用到临时表 提示服务器: 消息 9002,级别 17,状态 2,行 1 数据库 'tempdb' 的日志已满。请备份该数据库的事务日志以释放一些日志空间。 网上找了下解决方案,大体是扩大临时库的日志文件...

      SQL Server 临时表用法 object_id sysobjects tempdb dbo #temp

      临时表存储在tempdb中,当不再使用时会自动删除。临时表有两种类型:本地和全局。它们在名称、可见性以及可用性上有区别。 临时表有如下几个特点: 本地临时表就是用户在创建表的时候添加了”#”前缀的表,其特点是...

      关于SqlServer2000数据库中tempdb.mdf的迁移

      关于SqlServer2000数据库中tempdb.mdf的迁移

      SQL Server使用游标处理Tempdb究极竞争-DBA问题-程序员必知

      这里给大家剖析下游标在tempdb中的特点使其在一定场景下替代临时表/表变量对象,解决深层次的tempdb竞争问题. 在抛出这个不可避免的问题之前我们先简要看下什么是tempdb竞争. 我们拿SQL Server创建一个临时表的过程来...

      tempdb太大引起磁盘容量不足的解决方案.docx

      tempdb太大引起磁盘容量不足的解决方案

      恢复tempdb到安装初始化状态

      恢复tempdb数据库的方法要分两个部分。首先将tempdb重设到默认大小;其次确认和改变tempdb数据库到新的设备上

      tempdb:Redis支持的临时键值存储节点

      TempDB是Redis支持的Node临时键值存储。 这对于存储临时数据(例如登录代码,身份验证令牌和临时密码)很有用。 安装 npm install tempdb 运行Redis服务器 查看以为您的平台安装,或使用众多云提供商之一。 根据您...

      SQL Server 2014,表变量上的非聚集索引

      从Paul White的推特上看到,在SQL Server 2014里,对于表变量(Table Variables),它是支持非聚集索引(Non-Unique Clustered Indexes)和非聚集索引(Non-Clustered Indexes)的。看到这个,我决定在自己的虚拟机...

      如何恢复tempdb数据库.pdf

      如何恢复tempdb数据库.pdf

      数据库tempdb的日志已满

      数据库tempdb的日志已满数据库tempdb的日志已满

      如何查看SQLSERVER中某个查询用了多少TempDB空间

      外部使用(临时表,表变量等) 行版本控制(乐观并发控制)    而对于内部使用,一些比较复杂的查询中由于涉及到了大量的并行、排序等操作时就需要大量的内存空间,每一个查询在开始时都会由SQL Server预估需要...

      sql server 临时表 查找并删除的实现代码

      if exists(select * from tempdb..sysobjects where id=object_id(‘tempdb..#temp’)) drop table #temp临时表 可以创建本地和全局临时表。本地临时表仅在当前会话中可见;全局临时表在所有会话中都可见。 本地临时...

      如何查看某个查询用了多少TempDB空间

       · 外部使用(临时表,表变量等)  · 行版本控制(乐观并发控制)  而对于内部使用,一些比较复杂的查询中由于涉及到了大量的并行、排序等操作时需要大量的内存空间,每一个查询在开始时都会由SQL Server...

      SQL Server 2008 新特性 总结复习(一)

      1. TVP, 表变量,临时表,CTE 的区别 TVP和临时表都是可以索引的,总是存在tempdb中,会增加系统数据库开销,而表变量和CTE只有在内存溢出时才会被写入tempdb中。对于数据量大,并且反复使用,反复进行查询关联的,...

      浅谈SQL Server 2016里TempDb的进步

      tempdb:是连接到 SQL Server 实例的所有用户都可用的全局资源,它保存所有临时表,临时工作表,临时存储过程,临时存储大的类型,中间结果集,表变量和游标等。另外,它还用来满足所有其他临时存储要求.

    Global site tag (gtag.js) - Google Analytics