`
北极的。鱼
  • 浏览: 159021 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

【转】临时表vs.表变量以及它们对SQLServer性能的影响

 
阅读更多

转自:http://www.windbi.com/showtopic-90.aspx

 

在临时表
create table #T (…)
和表变量
declare @T table (…)
之间主要有 3 个理论上的不同。

第一个 不同使事务日志不会记录表变量。因此,它们脱离了事务机制的范围,从下面的例子可显而易见:

create table #T (s varchar(128))
declare @T table (s varchar(128))
insert into #T select 'old value #'
insert into @T select 'old value @'
begin transaction
    update #T set s='new value #'
    update @T set s='new value @'
rollback transaction
select * from #T
select * from @T

s
---------------
old value #

s
---------------
new value @


在声明临时表 #T 和表变量 @T 之后,给它们分配一个相同的值为 old value 字符串。然后,开始一个事务去更新它们。此时,它们都将有新的相同的值 new value 字符串。但当事务回滚时,正如你所看到的,表变量 @T 保留了这个新值而没有返回 old value 字符串。这是因为即使表变量在事务内被更新了,它本身不是事务的一部分。

第二个 主要的不同是任何一个使用临时表的存储过程都不会被预编译,然而使用表变量的存储过程的执行计划可以预先静态的编译。预编译一个脚本的主要好处在于加快了执行的速度。这个好处对于长的存储过程更加显著,因为对它来说重新编译代价太高。

最后 ,表变量仅存在于那些变量能存在的相同范围内。和临时表相反,它们在内部存储过程和 exec string )语句里是不可见的。它们也不能在 insert/exec 语句里使用。

性能比较

首先,准备一个有 100 万记录的测试表:

create table NUM (n int primary key, s varchar(128))
GO
set nocount on
declare @n int
set @n=1000000
while @n>0 begin
    insert into NUM
          select @n,'Value: '+convert(varchar,@n)
    set @n=@n-1
    end
GO


准备测试存储过程 T1

create procedure T1
    @total int
as
    create table #T (n int, s varchar(128))
    insert into #T select n,s from NUM
          where n%100>0 and n<=@total
    declare @res varchar(128)
    select @res=max(s) from NUM
          where n<=@total and
              not exists(select * from #T
              where #T.n=NUM.n)
GO


使用参数从 10 100 1000 10000 100000 1000000 不等来调用,它复制给定数量的记录到临时表(一些另外,它跳过那些能被 100 整除的数值),然后找到缺失记录的最大值。当然,记录越多,执行的时间就越长:
为了测量正好的执行时间,使用下面的代码:

declare @t1 datetime, @n int

set @t1=getdate()
set @n=
100 – (**)
while @n>0 begin
    exec T1
1000 – (*)
    set @n=@n-1 end
select datediff(ms,@t1,getdate())
GO


* )表示程序里边的参数从 10 1000000 不等。
** )表示如果执行时间太短,就重复相同的循环 10 100 次不等。

多次运行代码以获得执行的结果。

该结果在下面的表 1 里能找到。

下面试着给临时表添加一个主键来提升存储过程的性能:

create procedure T2

    @total int
as
    create table #T (n int
primary key , s varchar(128))
    insert into #T select n,s from NUM
          where n%100>0 and n<=@total
    declare @res varchar(128)
    select @res=max(s) from NUM
          where n<=@total and
              not exists(select * from #T
              where #T.n=NUM.n)
GO


然后,创建第三个。此时有聚集索引,它会工作得更好。但是是在插入数据到临时表之后创建的索引——通常,这样会更好:

create procedure T3
    @total int
as
    create table #T (n int, s varchar(128))
    insert into #T select n,s from NUM
          where n%100>0 and n<=@total
    create clustered index Tind on #T (n)
    declare @res varchar(128)
    select @res=max(s) from NUM
          where n<=@total and
              not exists(select * from #T
              where #T.n=NUM.n)
GO


令人惊奇!大数据量花费的时间很长;仅仅添加 10 条记录就花费了 13 毫秒。这个问题在于创建索引语句强迫 SQLServer 去重新编译存储过程,显著的降低了执行效率。

现在试着使用表变量来完成相同的事情:

create procedure V1
    @total int
as
    declare @V table (n int, s varchar(128))
    insert into @V select n,s from NUM
          where n%100>0 and n<=@total
    declare @res varchar(128)
    select @res=max(s) from NUM
          where n<=@total and
              not exists(select * from
@V V
              where V.n=NUM.n)
GO


使我们惊奇的是,该版本不是明显的比用临时表的快。这是由于在存储过程开头创建表 #T 语句时进行了特别优化的缘故。对整个范围内的值, V1 T1 工作得一样好。

下面试试有主键的情形:

create procedure V2
    @total int
as
    declare @V table (n int
primary key , s varchar(128))
    insert into @V select n,s from NUM
          where n%100>0 and n<=@total
    declare @res varchar(128)
    select @res=max(s) from NUM
          where n<=@total and
              not exists(select * from @V V
              where V.n=NUM.n)
GO


这个结果很快,但 T2 超过了该版本。

 

 

Records

T1

T2

T3

V1

V2

10

0.7

1

13.5

0.6

0.8

100

1.2

1.7

14.2

1.2

1.3

1000

7.1

5.5

27

7

5.3

10000

72

57

82

71

48

100000

883

480

580

840

510

1000000

45056

6090

15220

20240

12010


1 :使用 SQLServer2000 ,时间单位毫秒

但真正使我们震惊的是在 SQLServer2005 上的情形:

N

T1

T2

T3

V1

V2

10

0.5

0.5

5.3

0.2

0.2

100

2

1.2

6.4

61.8

2.5

1000

9.3

8.5

13.5

168

140

10000

67.4

79.2

71.3

17133

13910

100000

700

794

659

Too long!
Too long!

1000000

10556

8673

6440

Too long!
Too long!

2 :使用 SQLServer2005 (时间单位毫秒)

有时, SQL2005 SQL2000 快(上面标记为绿色的部分)。但大多数情况下,特别是在数据量巨大时,存储过程使用表变量花费了更长的时间(红色部分)。在 4 种情形下,我甚至放弃了等待。

结论

  • 在什么时候和什么地方使用临时表或表变量没有一个普遍的规则。试着都测试测试它们。
  • 在你的测试里,少量的记录和大量的数据集都要进行测试。
  • 当在你的存储过程里使用了复杂的逻辑的时候要小心迁移到 SQL2005 。相同的代码在 SQLServer2005 上可能运行要慢 10 100 倍。
分享到:
评论

相关推荐

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

    资源名称:SQLServer中临时表与表变量的区别内容简介: 本文档主要讲述的是SQLServer中临时表与表变量的区别;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看。资源截图: 资源太大,传百度网盘了,...

    SQL SERVER临时表的语法.pdf

    SQL Server的临时表是数据库操作中非常实用的工具,它们用于存储临时数据,尤其是在复杂的查询和数据处理过程中。临时表的语法和永久表类似,但它们具有不同的生命周期和存储位置。 1. **创建和删除临时表** - `...

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

    在SQL Server中,临时表和表变量是两种用于暂存数据的结构,它们在数据库操作中扮演着重要的角色。理解它们的区别有助于优化存储过程和提高性能。 临时表类似于永久表,但它们存在于Tempdb系统数据库中,仅在创建它...

    SQLServer中临时表与表变量的区别.docx

    ### SQL Server 中临时表与表变量的区别 #### 一、临时表 临时表与常规的永久表非常相似,主要区别在于其创建位置和生命周期。在SQL Server中,临时表是在`tempdb`数据库中创建的,这意味着它们仅在这个特定会话...

    SQL SERVER临时表的使用.pdf

    总的来说,SQL Server的临时表提供了一种灵活的方式来处理暂时性的数据,它们在处理复杂业务逻辑、临时存储中间结果以及在存储过程和函数中复用数据时尤其有用。了解并熟练使用临时表可以显著提升SQL Server数据库...

    sqlserver 循环临时表插入数据到另一张表

    sqlserver 循环临时表插入数据到另一张表 -- 声明变量 DECLARE @SupCode as varchar(100), @ProdCode as varchar(50), @PackLayer as varchar(50), @CodeStatus as varchar(50), @ProductId as varchar(50), @...

    SQL SERVER临时表的使用.docx

    与本地临时表不同,全局临时表在整个SQL Server实例中对所有会话可见。但是,它们的生命周期更为复杂,只有当创建它们的会话结束并且没有其他会话再引用它们时,全局临时表才会被自动删除。 临时表的一个常见用途是...

    SQL SERVER临时表的语法.docx

    SQL Server中的临时表是...正确地使用局部和全局临时表,以及根据需求选择表变量,能够优化数据库的性能并提高代码的可维护性。在实际应用中,应根据数据量、使用范围和会话生命周期来决定何时使用哪种类型的临时表。

    sqlserver性能调优入门

    分析存储过程的执行计划,寻找可以优化的点,如减少不必要的JOIN操作、使用更高效的函数或算法,以及优化临时表和变量的使用。还可以考虑是否可以重写查询以利用并行处理或批量操作,以提高处理速度。 总的来说,...

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

    在SQL Server中,表变量和临时表都是用来存储数据的临时结构,但它们在使用上存在显著的区别。本文将详细探讨这两个概念。 首先,我们来看看表变量。表变量是在SQL Server 2000中引入的新特性,它允许在批处理语句...

    SQLSERVER数据库性能优化分析

    ### SQLSERVER数据库性能优化分析 #### 一、问题分析 **1.1 死锁** 在SQL Server数据库中,死锁是一种常见的性能问题。当多个事务互相等待对方释放资源时,就会形成死锁。例如,进程A锁定了资源B,进程B锁定了...

    SQL Server遍历表中记录的2种方法(使用表变量和游标)

    表变量在SQL Server中是一种临时存储数据的结构,它与临时表相似但作用范围更小,仅限于当前批处理或存储过程。以下是一个使用表变量的例子: ```sql DECLARE @temp TABLE (id INT IDENTITY(1, 1), Name VARCHAR(10...

    SQLServer期末考试题目及答案.docx

    Transact-SQL 是 SQL Server 2000 的扩展语言,提供了程序控制结构、变量和函数等功能。 9. SQL Server 2000 字符型系统数据类型 SQL Server 2000 的字符型系统数据类型主要包括 char、varchar 和 text 等。 10. ...

    浅析SQL Server数据库的性能优化方法.pdf

    复杂的查询语句应当分解为多个简单的查询,并使用临时表和表变量来优化性能。 4. 应用程序结构优化 应用程序的设计直接影响数据库的使用效率。例如,事务应该尽可能小,并且及时关闭不必要的数据库连接。在设计查询...

    sql临时表相关介绍

    SQL临时表是数据库操作中的一种实用工具,它们用于在处理大量数据或进行复杂查询时提供暂时的数据存储空间。临时表分为两种类型:本地临时表和全局临时表。 1. **本地临时表**:本地临时表的名称以单个井字号 (#) ...

    SQL Tuning sqlServer 数据库

    - **临时表和表变量**:在适当的情况下,使用临时表或表变量来优化复杂查询。 5. **存储过程和函数**: - **存储过程的优势**:减少网络传输,提升安全性,封装业务逻辑。 - **函数优化**:考虑函数的执行效率,...

    mysql和SQLserver区别.docx

    在 SQL Server 中,可以使用 declare 语句来定义游标,而在 MySQL 中,需要使用 declare 语句来定义游标,并且需要使用 create temporary table 语句来创建临时表。 MySQL 和 SQL Server 都是关系型数据库管理系统...

Global site tag (gtag.js) - Google Analytics