是的,大量数据,会使用tempdb缓存数据。定义表变量,SQL内部肯定会定义临时表:declare @tb table (id int)
select * from tempdb.sys.tables -- 有一个临时表
goselect * from tempdb.sys.tables -- 没了
go表变量与临时表的主要区别是生命周期不同,另外索引方面表变量不如临时表。
select * from tempdb.sys.tables -- 有一个临时表
goselect * from tempdb.sys.tables -- 没了
go表变量与临时表的主要区别是生命周期不同,另外索引方面表变量不如临时表。
这是除了存储位置之外的第二大误解了。表变量绝对是存在于tempdb的。这个问题不知道有多少人争吵过,但是表变量存放在TempDB中是绝对可以肯定的。还有我始终不认为作用域不同时表变量和临时表最重要的区别。最重要的区别肯定是难以发现的。什么作用域不同,能建索引和不能建索引,sp_exectesql临时表支持,表变量不支持,insert into exec 临时表可以,表变量不可以。 都是直接能看到和平时用的时候碰到的。 我感觉他们最大的区别是 一个会产生统计信息一个不会。
create table #t(id int);
go
insert into #t
select 1goselect
session_id,
database_id,
user_objects_alloc_page_count
from sys.dm_db_session_space_usage
where session_id>50/*
52 2 9
*/declare @t table (id int)
insert into @t select 1goselect
session_id,
database_id,
user_objects_alloc_page_count
from sys.dm_db_session_space_usage
where session_id>50/*
52 2 10
*/
为什么又多分配了一页数据,因为表变量数据写在TempDB中。
像这样的问题以后还是少提吧。网上以前就有好多因为这个吵架的!
不知道有没有人攻击我类。 先闪人!
,CASE database_id
WHEN 32767 THEN 'ResourceDb'
ELSE db_name(database_id)
END AS database_name
FROM sys.dm_os_buffer_descriptors where database_id=2
GROUP BY db_name(database_id) ,database_id
ORDER BY cached_pages_count DESC; declare @i int;
set @i=0;
declare @t table (id NCHAR(4000))
while @i<1000
begin
insert into @t select replicate('A',4000)
set @i=@i+1;
end;
SELECT COUNT(*)AS cached_pages_count
,CASE database_id
WHEN 32767 THEN 'ResourceDb'
ELSE db_name(database_id)
END AS database_name
FROM sys.dm_os_buffer_descriptors where database_id=2
GROUP BY db_name(database_id) ,database_id
ORDER BY cached_pages_count DESC;
甚至SQL server也是个被严重误解、低估的数据库系统(主要是在国内)。
案例中用到的DMV: sys.dm_os_buffer_descriptors 应该是跟内存(buffer pool)有关的喔.
参考 http://msdn.microsoft.com/en-us/library/ms173442(v=sql.105).aspx之前做过测试: 用大循环,给一个表变量循环插入记录, 用windows性能监视器, 可以看到从程序执行那一刻起, 内存是线性增长的..
如果中止sql引擎的自动优化?select * from x where a=1
只有几十条结果,花了3秒钟select * from x where a=1 and b=2
结果更少,但是花了90秒!select * from (
select * from x where a=1) a
where b=2
仍然花了90秒!
感觉是sql编译器自作主张把b=2优化为与a=1一起执行了只有先把a=1的结果插入临时表,才能阻断sql的自作主张的优化:
select * into #t from x where a=1
select * from #t where b=2
只需3秒!(当然,实际的sql要复杂很多,但是的确可以、也应该分步执行的)这个问题遇到过几次了,不知道t-sql有没有什么语法让b=2不参与a=1的执行?
比如我把数据内存最大值设置到100M,定义一个1G的表变量
创建成功了,而且tempdb变大了,文件就涨 2G,而且通过性能计数器明显的看到了
tempdb 文件有明显的写入。
这个可以说明它放到tempdb里面去了吧我是比较好奇它什么时候会存在于内存中MS没有明确的文档说明,搞的大家全靠猜,议论纷纷也很正常
好吧,还是从我上面的举的例子说起,
declare @i int;
set @i=0;
declare @t table (id NCHAR(4000))
while @i<1000
begin
insert into @t select replicate('A',4000)
set @i=@i+1;
end;
上面的例子产生了1000个页面,那@t是在哪里产生的呢?
@t在tempdb 实例化,并且最初在BPOOL中产生,并且在checkpoint发生之前,它就已经存在于tempdb 中了,虽然它还没有刷入磁盘,但是它还是存在于tempdb中。 当然在checkpoint后生之后,BPOOL中的数据被输入磁盘,但是不管有没有发生checkpoint,数据有没有被输入磁盘,换句话说,无论@t只存是在BPOOL中,还是同时存在于BPOOL与磁盘,或者只存在于磁盘,@t它都存在于tempdb中。
理解上面这句话是理解准确存储引擎的关键之一。这也就是为什么上面使用DMV: sys.dm_os_buffer_descriptors 中,它对于的database_id为2,2就是tempdb嘛这也就可以解释MSDN上的那句话了,“Table variables are created in the tempdb database similar to temporary tables. If memory is available, both table variables and temporary tables are created and processed while in memory (data cache).
”
http://support.microsoft.com/kb/305977/en-us
当然假如把上面的表变量变成用户表,USE useRDB
GO
declare @i int;
set @i=0;
CREATE TABLE (id NCHAR(4000))
while @i<1000000
begin
insert into t select replicate('A',4000)
set @i=@i+1;
end;
假如你的系统是干净的,比如说刚重启,你也会通过管理器看到working set在 不断增长,很简单嘛,数据一开始是放入BPOOL的,而BPOOL就是内存的一部分,随着记录的增多,BPOOL的需求量越来越大,working set就越来越高咯。
前辈可否有空看下我提的关于进程状态dormant的问题呢~不胜感激啊~
这是除了存储位置之外的第二大误解了。表变量绝对是存在于tempdb的。这个问题不知道有多少人争吵过,但是表变量存放在TempDB中是绝对可以肯定的。还有我始终不认为作用域不同时表变量和临时表最重要的区别。最重要的区别肯定是难以发现的。什么作用域不同,能建索引和不能建索引,sp_exectesql临时表支持,表变量不支持,insert into exec 临时表可以,表变量不可以。 都是直接能看到和平时用的时候碰到的。 我感觉他们最大的区别是 一个会产生统计信息一个不会。
create table #t(id int);
go
insert into #t
select 1goselect
session_id,
database_id,
user_objects_alloc_page_count
from sys.dm_db_session_space_usage
where session_id>50/*
52 2 9
*/declare @t table (id int)
insert into @t select 1goselect
session_id,
database_id,
user_objects_alloc_page_count
from sys.dm_db_session_space_usage
where session_id>50/*
52 2 10
*/
为什么又多分配了一页数据,因为表变量数据写在TempDB中。
像这样的问题以后还是少提吧。网上以前就有好多因为这个吵架的!
不知道有没有人攻击我类。 先闪人!
看你们争吵那么激烈我又回来了,
还引用自己上面的例子来回答9楼, 使用表变量导致 数据库id为2 的tempdb中又多分配了一页,
就能证明表变量不是在内存中创建的。 你的另一个问题(DMV: sys.dm_os_buffer_descriptors 应该是跟内存(buffer pool)有关的喔)
你说的很对这个视图是跟bpool有关,表变量和临时表也是要被缓存的呀,跟其他表一样啊,除非服务器内存很紧张和使用特别大的表,不管怎么样都将在内存中使用这些表。表变量在tempdb里被缓存了就能在这个视图里找到它。也能够得到它的数据库ID为2
如果没有被刷入磁盘,那么tempdb为什么能看到有新的Page产生,没刷入磁盘,怎么不算内存中的,却要说是以物理的形式存在于tempdb中
如果没有被刷入磁盘,那么tempdb为什么能看到有新的Page产生,没刷入磁盘,怎么不算内存中的,却要说是以物理的形式存在于tempdb中
没有被刷入磁盘,算内存中的,但是也算在tempdb中的,并不是说被刷入磁盘才算存在于tempdb中,tempdb的存在形式并不是只算磁盘,上面已经强调过了。
如果没有被刷入磁盘,那么tempdb为什么能看到有新的Page产生,没刷入磁盘,怎么不算内存中的,却要说是以物理的形式存在于tempdb中
没有被刷入磁盘,算内存中的,但是也算在tempdb中的,并不是说被刷入磁盘才算存在于tempdb中,tempdb的存在形式并不是只算磁盘,上面已经强调过了。
貌似很牛逼的样子,有点理解了,再问一个问题啊,如果是一个表变量,但是被刷入磁盘后,然后超出了这个变量作用域后,变量就被销毁了,那是不是要删除原先写入磁盘中的数据,临时表应该也是一样的吧?
如果没有被刷入磁盘,那么tempdb为什么能看到有新的Page产生,没刷入磁盘,怎么不算内存中的,却要说是以物理的形式存在于tempdb中
没有被刷入磁盘,算内存中的,但是也算在tempdb中的,并不是说被刷入磁盘才算存在于tempdb中,tempdb的存在形式并不是只算磁盘,上面已经强调过了。
貌似很牛逼的样子,有点理解了,再问一个问题啊,如果是一个表变量,但是被刷入磁盘后,然后超出了这个变量作用域后,变量就被销毁了,那是不是要删除原先写入磁盘中的数据,临时表应该也是一样的吧?
你虽问的不是小菜鸟的我。
但是这个我正好见过。不知道是不是你想要的答案。我回答的也不一定对撒?其实你问的是数据,所有的数据都要在内存中才能被使用啊,修改插入其他数据页都是一样的啊。整个事务唯一写入磁盘的是LOG文件,数据是先写在内存里,而后经过checkpoint或懒惰写来刷入磁盘的。 至于你说的回收那我感觉它既然在tempdb里就要遵守tempdb回收的策略。 比如版本存储区60秒回收一次,当然它不回收活动的事务,如你这个事务已经提交了sqlserver会通过跟踪保存在保存在版本存储区中最小事务序列号来完成这个工作,对序列号小于这个值的事务进行批量删除。sys.dm_tran_current_transaction 中first_useful_sequence_num来告诉我们事务序列号。 当然上面只是回答了版本存储区回收机制,
tempdb 放三种对象:用户临时对象(临时表,表变量),内部临时对象(排序,散列连接,游标),版本存储区(触发器,快照隔离和读提交快照隔离,联机索引,多活动结果集)用户临时对象我感觉session对开后释放。
排序,散列我感觉语句执行完成后释放。
版本存储区 上面已经说了
http://blog.csdn.net/roy_88/article/details/8461942
那考考大家,根据34楼,
表变量的insert操作是产生日志的,但是回滚事务对表变量无效,既然回滚事务对表变量是无效的 ,那还要产生日志干什么?
如果没有被刷入磁盘,那么tempdb为什么能看到有新的Page产生,没刷入磁盘,怎么不算内存中的,却要说是以物理的形式存在于tempdb中
没有被刷入磁盘,算内存中的,但是也算在tempdb中的,并不是说被刷入磁盘才算存在于tempdb中,tempdb的存在形式并不是只算磁盘,上面已经强调过了。
貌似很牛逼的样子,有点理解了,再问一个问题啊,如果是一个表变量,但是被刷入磁盘后,然后超出了这个变量作用域后,变量就被销毁了,那是不是要删除原先写入磁盘中的数据,临时表应该也是一样的吧?
你虽问的不是小菜鸟的我。
但是这个我正好见过。不知道是不是你想要的答案。我回答的也不一定对撒?其实你问的是数据,所有的数据都要在内存中才能被使用啊,修改插入其他数据页都是一样的啊。整个事务唯一写入磁盘的是LOG文件,数据是先写在内存里,而后经过checkpoint或懒惰写来刷入磁盘的。 至于你说的回收那我感觉它既然在tempdb里就要遵守tempdb回收的策略。 比如版本存储区60秒回收一次,当然它不回收活动的事务,如你这个事务已经提交了sqlserver会通过跟踪保存在保存在版本存储区中最小事务序列号来完成这个工作,对序列号小于这个值的事务进行批量删除。sys.dm_tran_current_transaction 中first_useful_sequence_num来告诉我们事务序列号。 当然上面只是回答了版本存储区回收机制,
tempdb 放三种对象:用户临时对象(临时表,表变量),内部临时对象(排序,散列连接,游标),版本存储区(触发器,快照隔离和读提交快照隔离,联机索引,多活动结果集)用户临时对象我感觉session对开后释放。
排序,散列我感觉语句执行完成后释放。
版本存储区 上面已经说了
如果没有被刷入磁盘,那么tempdb为什么能看到有新的Page产生,没刷入磁盘,怎么不算内存中的,却要说是以物理的形式存在于tempdb中
没有被刷入磁盘,算内存中的,但是也算在tempdb中的,并不是说被刷入磁盘才算存在于tempdb中,tempdb的存在形式并不是只算磁盘,上面已经强调过了。
貌似很牛逼的样子,有点理解了,再问一个问题啊,如果是一个表变量,但是被刷入磁盘后,然后超出了这个变量作用域后,变量就被销毁了,那是不是要删除原先写入磁盘中的数据,临时表应该也是一样的吧? 上面自己说的有错误,能不能从新解释一下子。tempDB是不参与checkpoint的,我上面却说checkpoint的时候表变量里的脏数据页刷入磁盘。这里说声 i'm sorry。tempdb只在内存压力比较大的写入磁盘而不是checkpoint。
tempdb虽然只记录undo,也就是只能undo不能redo,就是只能回滚。至于表变量为何不能回滚是:表变量是不参与日志记录的。不维护统计信息,不能生成并行的查询计划,不允许DDL运行,不能参与事务处理和锁定。