[SQL]解決大量資料刪除,造成資料庫交易紀錄檔案容量過大且耗費時間之處理

[SQL]解決大量資料刪除,造成資料庫交易紀錄檔案容量過大且耗費時間之處理

這幾天遇到一個蠻特別的狀況,因此將相關處理和數據模擬整理一下,避免以後遇到類似狀況的時候,就可以請相關人員自己來看說明了,能有多一點時間來看 R 語言了。

 

前置準備

話說這個案例是這樣的,有一個數據庫內有不少的資料表,會定時將內部很多的資料給刪除,然後再重新匯入新的資料。由於其中部份的資料表數據都至少有數百萬筆以上,因此時常因為刪除資料的時候,交易紀錄檔案成長非常的大,耗用掉非常大的硬碟空間,因此希望能找到比較好的解決方式,為了重現這個問題,我們先用以下的指令來建立一個模擬的資料庫。

 

-- 刪除範例資料庫
 IF DB_ID('SPTEST') IS NOT NULL DROP DATABASE [SPTEST];
 GO 
  
 -- 建立資料庫
 CREATE DATABASE [SPTEST]
 GO
  
 -- 變更復原模式為簡單
 ALTER DATABASE [SPTEST] SET RECOVERY SIMPLE;
 GO
  

 USE [SPTEST]
 GO
  
 -- 建立資料表
 CREATE TABLE [BigTable]
 (
     A1    INT,
     A2    NVARCHAR(10),
     A3    VARCHAR(10),
     A4    NCHAR(200),
 )
 GO
  
 DECLARE @I INT;
 DECLARE @J INT;
 DECLARE @K INT;
  
  
 SET @J = 0;
  
 -- 產生一千萬筆的資料,為了避免交易記錄檔過大,每一萬筆資料放在一個 Transaction 內
 SET NOCOUNT ON;
 WHILE @J < 1000
 BEGIN
     SET @I = 0;
     BEGIN TRAN
     WHILE @I < 10000 
     BEGIN
         SET @K = @J*10000+@I ;
         INSERT INTO [BigTable] ( A1,A2,A3,A4 ) VALUES ( @K, RIGHT('0000000000'+LTRIM(STR(@K)),10), RIGHT('0000000000'+LTRIM(STR(@K)),10), NEWID())
         SET @I += 1; 
     END    
     COMMIT
     SET @J += 1; 
 END
 GO

為了方便後續測試有一樣的基準,因此我先將該資料庫給備份起來,留做每次都可以還原來使用

USE [master]
GO

BACKUP DATABASE [SPTEST] TO DISK= 'D:\Temp\SPTEST_FULL.BAK'  WITH INIT, FORMAT, COMPRESSION
GO

 

這樣的資料庫差不多占用 5GB 的磁碟空間

image


 

進行測試

基本上交易紀錄檔案會成長,主要跟資料庫復原模式有關係,因此我們先測試在復原模式是「完整」和「簡單」的狀況下,當刪除資料會耗用多少時間與占用多大的交易紀錄檔案。首先我們先測試復原模式是「完整」

USE [master]
GO
RESTORE DATABASE [SPTEST] FROM DISK = 'D:\TEMP\SPTEST_FULL.BAK' WITH REPLACE
GO

ALTER DATABASE [SPTEST] SET RECOVERY FULL WITH NO_WAIT
GO

BACKUP DATABASE [SPTEST] TO DISK='NUL'
GO

USE [SPTEST]
GO

DECLARE @Start DATETIME = GETDATE()
DELETE FROM  [dbo].[BigTable]
PRINT DATEDIFF( ss, @Start, GETDATE() )

 

結果如下,可以看到執行刪除指令耗用 102 秒的時間

image

 

而交易紀錄檔案大小成長到 14GB 的大小

image

 

那如果復原模式是採用「簡單」的時候,狀況會是如何呢 ?

USE [master]
GO
RESTORE DATABASE [SPTEST] FROM DISK = 'D:\TEMP\SPTEST_FULL.BAK' WITH REPLACE
GO

ALTER DATABASE [SPTEST] SET RECOVERY SIMPLE WITH NO_WAIT
GO

BACKUP DATABASE [SPTEST] TO DISK='NUL'
GO

USE [SPTEST]
GO

DECLARE @Start DATETIME = GETDATE()
DELETE FROM  [dbo].[BigTable]
PRINT DATEDIFF( ss, @Start, GETDATE() )

耗用時間差不多

image

 

而占用的空間也差異不大

image

 

主要是因為不管是復原模式是「完整」或「簡單」,因為交易資料都要先寫入到交易紀錄檔案內,而刪除資料筆數和環境都相同,因此兩者占用的空間和時間都差異不大。而如果真的要講求快速的話,那麼使用 TRUNCATE TABLE 是最快的,但限制就是只能全部刪除的狀況下使用,由於我們的案例只是刪除部分資料,加上又不是 Enterprise 的版本的情況下,是沒有辦法使用 Partition Table 的方式,因此下面的案例中我們都使用 DELETE 來做處理。

image


 

平行成本

而為了避免交易紀錄檔案占用那麼多的空間和時間,我們先查看一下刪除指令的「估計執行計畫」,從下圖中可以看出這樣的刪除指令很大量的耗用 IO 成本,使得運算子成本很容易高於系統「平成處理原則的成本臨界值」的預設值 5,因此我們可以試試看利用 MAXDOP 限制只使用單核心來做處理。

image

 

USE [master]
GO
RESTORE DATABASE [SPTEST] FROM DISK = 'D:\TEMP\SPTEST_FULL.BAK' WITH REPLACE
GO

ALTER DATABASE [SPTEST] SET RECOVERY FULL WITH NO_WAIT
GO

BACKUP DATABASE [SPTEST] TO DISK='NUL'
GO

USE [SPTEST]
GO

DECLARE @Start DATETIME = GETDATE()
DELETE FROM  [dbo].[BigTable] OPTION ( MAXDOP 1 )
PRINT DATEDIFF( ss, @Start, GETDATE() )

 

看起來對時間有點幫助,縮減了不少

image

 

就算復原模式是簡單的時候也能有幫助

image


 

批次刪除

但因為交易紀錄檔案還是會成長,因此我們下面會採用批次刪除的方式,配合復原模式是簡單的狀況下,用不同的批量來進行測試。

 

首先是一次 10,000 筆資料,將耗用 497 秒,交易紀錄檔案會是 43MB

image

image

 

當批量為 50,000 筆的時候,時間是 54 秒,交易紀錄檔案會是 199MB

image

image

 

當批量為 100,000 筆的時候,時間是 42 秒,交易紀錄檔案會是 320MB

image

image


 

總結

為了方便了解相關變化,我將上面的測試數據整理成為表格,當然這樣的測試數據會跟許多環境變數而所有改變,像是磁碟的速度、電腦運算的速度、記憶體大小、一筆記錄的大小等原因,都有可能造成不同的結果出現。但一般狀況下如果沒有需要做到交易紀錄備份或者是其他 HADR 的解決方案時,當採用復原模式是簡單的狀況下,如果有大量資料需要刪除的時候,最好加上核心數的限制和採用批量刪除,將可以更有效的提升效能,也避免交易紀錄檔案過大的問題。

image