插入期間磁碟空間已滿,會發生什麼?
今天我發現儲存我的數據庫的硬碟已滿。這種情況以前發生過,通常原因很明顯。通常有一個錯誤的查詢,這會導致 tempdb 大量溢出,直到磁碟已滿。這次發生的事情不太明顯,因為 tempdb 不是驅動器滿的原因,而是數據庫本身。
事實:
- 通常的數據庫大小約為 55 GB,它增長到 605 GB。
- 日誌文件大小正常,數據文件很大。
- 數據文件有 85% 的可用空間(我將其解釋為“空氣”:已使用但已釋放的空間。一旦分配,SQL Server 將保留所有空間)。
- Tempdb 大小正常。
我找到了可能的原因;有一個查詢選擇了太多的行(錯誤的連接會導致選擇 110 億行,而預計會有幾十萬行)。這是一個
SELECT INTO
查詢,這讓我想知道是否會發生以下情況:
- SELECT INTO 被執行
- 目標表已創建
- 數據在選擇時插入
- 磁碟已滿,導致插入失敗
- SELECT INTO 被中止並回滾
- 回滾釋放空間(已插入的數據被刪除),但 SQL Server 不會釋放釋放的空間。
然而,在這種情況下,我不會期望由創建的表
SELECT INTO
仍然存在,它應該被回滾刪除。我測試了這個:BEGIN TRANSACTION SELECT T.x INTO TMP.test FROM (VALUES(1))T(x) ROLLBACK SELECT * FROM TMP.test
這導致:
(1 row affected) Msg 208, Level 16, State 1, Line 8 Invalid object name 'TMP.test'.
然而目標表確實存在。實際查詢不是在顯式事務中執行的,這可以解釋目標表的存在嗎?
我在這裡勾勒的假設是否正確?這是可能發生的情況嗎?
實際查詢不是在顯式事務中執行的,這可以解釋目標表的存在嗎?
是的,正是如此。
如果您在 a
select into
之外執行一個簡單的操作explicit transaction
,則在自動送出模式下有兩個transactions
:第一個創建 thetable
,第二個填充它。您可以通過以下方式向自己證明:
在一個專用
database
的測試伺服器上simple recovery model
,首先製作一個checkpoint
並確保日誌只包含與checkpoint
. 然後執行select into
一行並log
再次檢查,尋找begin tran
關聯的select into
:checkpoint; select * from sys.fn_dblog(null, null); select 'a' as col into dbo.t3; select * from sys.fn_dblog(null, null) where Operation = 'LOP_BEGIN_XACT' and [Transaction Name] = 'SELECT INTO';
你會得到 2 行,表明你有 2
transactions
。我在這裡勾勒的假設是否正確?這是可能發生的情況嗎?
是的,他們是正確的。
was的
insert
部分,但它不釋放任何數據空間。您可以通過執行來驗證這一點;你會看到很多。select into``rolled back``sp_spaceused``unallocated space
如果您希望數據庫釋放這個未分配的空間,您應該使用
shrink
您的數據文件。