在使用sql server時您可能遇到過下面的情況,tempdb的數據文件初始大小為3mb, 隨着對tempdb的使用,tempdb文件逐漸變得很大(例如30GB),導致了磁盤空間不足。 此時您需要立刻釋放tempdb文件所占用的空間,這時你會有兩個選擇:
- 重啟SQL Server。大家都知道SQL Server重啟時會創建一個新的tempdb。由於tempdb的initial size並不會隨着文件大小的增長而增長,重啟SQL Server就會創建一個新的3MB的tempdb。
- 使用DBCC命令收縮tempdb的大小。如果當前tempdb實際被使用到的空間其實不大,只是文件尺寸很大的話,您可能會考慮使用dbcc shrinkfile來收縮tempdb。通常情況下,這種方案是可行。但是您需要警惕一個潛在的風險。下面是我最近遇到的一個實際的案例。
客戶嘗試使用dbcc shrinkfile依然無法收縮,但發現tempdb大小沒有變化,仍然是30GB。客戶搜索到了下面的這篇文章:
Shrink TempDB Transaction Log fails after overflow http://blogs.technet.com/technet_blog_images/b/sql_server_sizing_ha_and_performance_hints/archive/2011/03/03/shrink-tempdb-transaction-log-fails-after-overflow.aspx
http://www.sqlservercentral.com/blogs/james-sql-footprint/2012/04/06/clean-sql-server-cache/
於是嘗試使用dbcc freesystemcache('ALL') , 然后使用dbcc shrinkfile,但發現tempdb仍然無法收縮。遇到這樣情況可能是因為在使用dbcc freesystemcache('ALL')時,依然有session在引用tempdb,所以無法清除所有的internal objects,導致無法收縮。於是客戶決定重啟sql server。奇怪的是,SQL Server重啟后,客戶發現tempdb沒有變回初始大小的3mb,而是依舊保持了30GB的尺寸。打開SSMS查看tempdb的初始大小,非常奇怪的,initial size變成了30GB…
為什么會出現這樣的結果呢?原因是dbcc shrinkfile會把tempdb的initial size設置為語句運行完之后tempdb文件的當前大小。所以當shrinkfile沒能成功收縮tempdb時,tempdb的initial size就變成了30GB,即使重啟SQL Server, tempdb依舊還是占用了30GB的空間。
因此在執行dbcc shrinkfile前要千萬小心咯。你需要確保沒有session引用tempdb的情況下執行dbcc freesystemcache('ALL'), 之后再進行收縮。如果無法保證,那么就只能通過執行alter database,將initial size縮小,然后重啟SQL Server來收縮tempdb了。Alter database語句如下:
alter database tempdb modify file(name='tempdev',size=10mb)
請注意,如果指定的size小於當前大小,文件是不會縮小的,但initial size會變成指定的size.
更多信息
===
- 需要注意的是,我們這里對tempdb的initial size的定義,是每次SQL Server重啟后重新創建出來的新的tempdb的初始大小。而不是你在SSMS的數據庫屬性界面中看到的initial size的值。我們認為只有重啟后tempdb的大小對用戶才是有意義的。
- dbcc shrinkfile變更initial size的行為是在sql server 2008中引入的。 在sql server 2005里,dbcc shrinkfile並不會改變initial size,所以即使無法收縮,重啟后tempdb也會變為之前的大小。
- 對於tempdb,當有新的數據插入並且現有可用空間無法容納新的數據時,tempdb文件會按照Autogrowth屬性進行增長,但是initial size並不會發生變化。那么initial size這個值到底存儲在哪里呢?很遺憾,我在BOL中沒有找到。 我嘗試在打開SSMS展示initial size時捕獲SQL Server trace, 但並沒有找到實際表initial size的列和語句。但從實際效果來看,我找到了相應的替代品:
DMV sys.master_files的size列表示initial size。select size,* from sys.master_files where database_id=2
DMV sys.database_files的size表示當前大小。select size ,*From tempdb.sys.database_files
- SQL Server 2012的SSMS顯示的tempdb的initial size和SQL Server重啟后重新生成的tempdb的初始大小可能是不同的。而SQL Server 2005/2008/2008 R2的SSMS沒有這個問題。根據第一點中我們對initial size的定義,建議如果要查看sql server 2012 tempdb的initial size,請使用DMVsys.master_files
- Alter database modify file語句改變tempdb的initial size的行為也是在sql server 2008(以及以后版本)中引入的。在2005中無法改變tempdb的initial size.
- Alter database modify file語句只可以改變tempdb的initial size,不會改變user database的initial size。當嘗試更改user database時,如果指定的size小於當前size,會拋出下面的錯誤:MODIFY FILE failed. Specified size is less than current size.
- dbcc shrinkfile (Transact-SQL) http://technet.microsoft.com/en-us/library/ms189493(v=sql.90).aspx
- dbcc shrinkfile (Transact-SQL) http://technet.microsoft.com/en-us/library/ms189493(v=sql.100).aspx
- How to shrink the tempdb database in SQLServer http://support.microsoft.com/kb/307487
上述討論所的知識點和技巧都是針對tempdb的,請不要將其應用於user database。關於user database的情況我會在后續的文章里介紹。