Sql-Server

插入期間磁碟空間已滿,會發生什麼?

  • March 15, 2019

今天我發現儲存我的數據庫的硬碟已滿。這種情況以前發生過,通常原因很明顯。通常有一個錯誤的查詢,這會導致 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'.

然而目標表確實存在。實際查詢不是在顯式事務中執行的,這可以解釋目標表的存在嗎?

我在這裡勾勒的假設是否正確?這是可能發生的情況嗎?

實際查詢不是在顯式事務中執行的,這可以解釋目標表的存在嗎?

是的,正是如此。

如果您在 aselect into之外執行一個簡單的操作explicit transaction,則在自動送出模式下有兩個transactions:第一個創建 the table,第二個填充它。

您可以通過以下方式向自己證明:

在一個專用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您的數據文件。

引用自:https://dba.stackexchange.com/questions/230491