SQL Server 变量表 临时表 分析

最近,我有一朋友,对我说他的数据库中的很多存储过程,执行都是超时.让我替他看看是什么原因.我一看,原来他的存储过程中用了很多的临时表与变量表.于是我跟他说过犹不及.

在存储过程中使用临时表或变量表,使用的好可以提高速度,使用的不好,可能会起到反作用. 然后给了他几个示例让他自己去看,然后针对自己的数据库进行修改.

那么表变量一定是在内存中的吗?不一定.

通常情况下,表变量中的数据比较少的时候,表变量是存在于内存中的。但当表变量保留的数据较多时,内存中容纳不下,那么它必须在磁盘上有一个位置来存储数据。与临时表类似,表变量是在tempdb 数据库中创建的。如果有足够的内存,则表变量和临时表都在内存(数据缓存)中创建和处理。

 说明:

     1) CPU-- 事件(sql语句)使用的 CPU 时间(毫秒)。

     2)  Reads--由服务器代表事件读取逻辑磁盘的次数。这些读取操作数包含在语句执行期间读取表和缓冲区的次数。

     3) Writes--由服务器代表事件写入物理磁盘的次数。

 

 

示例1.变量表

1) 10000条记录

declare @t table
(
id nvarchar(50),
supno nvarchar(50),
eta datetime
)
insert  @t

select top 10000 ID,supno,eta from 表

 

--cpu :125    reads :13868    writes: 147

--表 '#286302EC'。扫描计数 0,逻辑读取 10129 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

--表 '表'。扫描计数 1,逻辑读取 955 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

declare @t table
(
id nvarchar(50),
supno nvarchar(50),
eta datetime
)
insert  @t

select top 1000 ID,supno,eta from 表

 

--    cpu:46    reads:2101     writes:    17   
--表 '#44FF419A'。扫描计数 0,逻辑读取 1012 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
--表 '表'。扫描计数 1,逻辑读取 108 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。



--示例2。临时表:

 

create table #t
(
id nvarchar(50),
supno nvarchar(50),
eta datetime
)
end
insert #t
select top 10000 ID,supno,eta
from 表

--cpu :125    reads:13883       writes:148    
--表 '#t00000000005'。扫描计数 0,逻辑读取 10129 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
--表 '表'。扫描计数 1,逻辑读取 955 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。


create table #t
(
id nvarchar(50),
supno nvarchar(50),
eta datetime
)

insert #t
select top 1000 ID,supno,eta
from 表

--cpu: 62    reads: 2095        writes: 17

--表 '#t00000000003'。扫描计数 0,逻辑读取 1012 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
--表 '表'。扫描计数 1,逻辑读取 108 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。


 


--示例3。不创建临时表,直接插入到临时表

select top 10000 ID,supno,eta
into #t
from 表

--cpu:31    reads:1947        writes:83

--表 '表'。扫描计数 1,逻辑读取 955 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。




select top 1000 ID,supno,eta
into #t
from 表

--cpu: 0    reads: 997        writes:11

--表 '表'。扫描计数 1,逻辑读取 108 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

从以上的分析中可以看出,如果使用3)方式,则会少建一个临时表.那么IO中的读写也将减少次数.

1)与2)都会有先建临时表的动作,并进行相应的IO读取操作.

从sql语句对服务器的cpu使用上来看,第三种情况cpu使用率也相对较低.

从物理写入磁盘操作来看,第三种情况的物理写入次数较少.

 

在什么情况下使用表变量来代替临时表:

取决于以下三个因素:

插入到表中的行数。本人认为最好是小于1000行,具体情况具体分析.
从中保存查询的重新编译的次数。
查询类型及其对性能的指数和统计信息的依赖性。
在某些情况下,可将一个具有临时表的存储过程拆分为多个较小的存储过程,以便在较小的单元上进行重新编译。

个人建议,当记录行小于1000行的情况下,应尽量使用表变量,除非数据量非常大(大于1000行)并且需要重复使用表。在这种情况下,可以在临时表上创建索引以提高查询性能。但是,各种方案可能互不相同。

Microsoft 建议您做一个测试,来验证表变量对于特定的查询或存储过程是否比临时表更有效。


比较临时表及表变量都可以通过SQL的选择、插入、更新及删除语句,它们的的不同主要体现在以下这些: 


  1)表变量是存储在内存中的,当用户在访问表变量的时候,SQL Server是不产生日志的,而在临时表中是产生日志的; 


  2)在表变量中,是不允许有非聚集索引的; 


  3)表变量是不允许有DEFAULT默认值,也不允许有约束; 


  4)临时表上的统计信息是健全而可靠的,但是表变量上的统计信息是不可靠的; 


  5)临时表中是有锁的机制,而表变量中就没有锁的机制。 



其实在选择临时表还是表变量的时候,我们大多数情况下在使用的时候都是可以的,但一般我们需要遵循下面这个情况,选择对应的方式: 


  1)使用表变量主要需要考虑的就是应用程序对内存的压力,如果代码的运行实例很多,就要特别注意内存变量对内存的消耗。我们对于较小的数据或者是通过计算出来的推荐使用表变量。如果数据的结果比较大,在代码中用于临时计算,在选取的时候没有什么分组的聚合,就可以考虑使用表变量。 


  2)一般对于大的数据结果,或者因为统计出来的数据为了便于更好的优化,我们就推荐使用临时表,同时还可以创建索引,由于临时表是存放在Tempdb中,一般默认分配的空间很少,需要对tempdb进行调优,增大其存储的空间。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值