日期:2014-05-16 浏览次数:20428 次
作为一个支持工程师,会被经常问到象“我的Tempdb为什么这么大?”“是谁把我的Tempdb空间用完的?”在SQL 2000的时候,这个问题很难回答。好在SQL 2005以后,引入了一张新的管理视图:sys.dm_db_file_space_usage。通过查询这张视图,能了解tempdb的空间使用情况,能知道tempdb的空间是被哪一块对象使用掉的,是用户对象(user_object_reserved_page_count字段),还是系统对象(internal_object_reserved_page_count字段),还是版本存储区(version_store_reserved_page_count字段)。
在讨论Tempdb空间使用之前,我们先简单介绍一下通常什么操作会大量使用Tempdb。在SQL 2005和SQL 2008里,使用Tempdb空间的远远不止是临时表。常见的使用对象有:
用户对象(user_object_reserved_page_count)
用户对象由用户显式创建。这些对象可以位于用户会话的作用域中,也可位于创建对象所用例程的作用域中。 可以是存储过程、触发器或用户定义函数。 用户对象可以是下列项之一:
内部对象(internal_object_reserved_page_count)
内部对象是根据需要由 SQL Server 数据库引擎创建的,用于处理 SQL Server 语句。 内部对象可以在语句的作用域中创建和删除。 内部对象可以是下列项之一:
版本存储(version_store_reserved_page_count)
版本存储区主要用来支持Snapshot事务隔离级别,以及SQL 2005以后推出的一些其他提高数据库并发度的新功能。
由此可见,光从用户发过来的语句本身,是很难判断这个连接的操作是否会使用Tempdb的。一个典型的例子,就是某些查询。如果表格上有良好的索引做支持,SQL Server不需要做哈希联接(Hash Join),那这个查询就不会用Tempdb。反之,如果表格很大,又没有好的索引,那Tempdb使用量就可能不小。
tempdb空间使用的一大特点,是只有一部分对象,例如用户创建的临时表、table变量等,可以用sys.allocation_units 和sys.partitions这样的管理视图来管理。许多内部对象和版本存储在这些管理视图里没有体现。所以,sp_spaceused的结果和真实使用会有很大差异,tempdb的空间使用是不能用sp_spaceused来跟踪的。必须借助sys.dm_db_file_space_usage这样的管理视图和管理函数,才能看到全貌。
下面以一个实例,讨论一下如何用DBCC命令、管理视图(DMV)以及管理函数(DMF)来监视是什么语句正在使用tempdb。
为了使结果简单,我们在测试之前先把SQL Server重起一次。
然后我们在Management Studio里做一个连接(连接A),将下面语句输入。这些语句会使用tempdb的空间。
USE [My_Test_DB] go SELECT GETDATE() go SELECT * INTO #MyOrderSource FROM OrderSource AS o -- 创建一个temp table,OrderSource 是一个很大的表这样效果更明显 -- 这个操作应该会申请user objects page go WAITFOR DELAY '0:0:2' SELECT GETDATE() go DROP TABLE #MyOrderSource -- 删除一个temp table -- 这个操作后user object page数量应该会下降 go WAITFOR DELAY '0:0:2' SELECT GETDATE() go SELECT TOP 100000* FROM OrderSource AS o JOIN shippingOrder AS s ON o.OrderId=b.OrderId -- 这里做了一个比较大的join. -- 应该会有internal objects的申请. go SELECT GETDATE() -- join 语句做完以后internal objects page数目应该下降
那用什么脚本可用监视上面的行为呢?下面的脚本就可以监视和发现当前的Tempdb使用者。这个脚本需要在使用tempdb的语句开始运行之前开始。(读者当然可以根据自己的喜好,修改这个脚本。)
脚本首先用“dbcc showfilestats”语句查询当前tempdb的总体使用量。再查询sys.dm_db_file_space_usage视图,得到Tempdb里当前总共有多少用户对象、内部对象、以及版本存储。然后查询sys.dm_db_session_space_usage和sys.dm_exec_sessions,找到当前使用Tempdb的所有连接。最后通过sys.dm_exec_sql_text,找到这些连接正在运行的语句。
USE tempdb -- 每隔1秒钟运行一次,直到用户手工终止脚本运行 WHILE 1 = 1 BEGIN -- Query 1 -- 从文件级看tempdb使用情况 DBCC showfilestats -- Query 2 -- 返回所有做过空间申请的session信息 SELECT 'tempdb' AS database_name , GETDATE() AS Time , SUM(user_object_reserved_page_count)/128. AS user_objects_mb , SUM(internal_