DBCC SHRINKFILE (Transact-SQL)

適用於:SQL ServerAzure SQL DatabaseAzure SQL 受控執行個體

壓縮目前資料庫的指定資料或記錄檔大小。 您可以使用它將資料從某個檔案移至同一檔案群組中的其他檔案,其可清空檔案並允許移除其資料庫。 您可以將檔案壓縮成小於其在建立時的大小,將檔案大小下限重設為新值。

Transact-SQL 語法慣例

Syntax

DBCC SHRINKFILE   
(  
    { file_name | file_id }   
    { [ , EMPTYFILE ]   
    | [ [ , target_size ] [ , { NOTRUNCATE | TRUNCATEONLY } ] ]  
    }  
)  
[ WITH 
  {     
      [ WAIT_AT_LOW_PRIORITY 
        [ ( 
            <wait_at_low_priority_option_list>
        )] 
      ] 
      [ , NO_INFOMSGS]
  }
]
       
< wait_at_low_priority_option_list > ::=  
    <wait_at_low_priority_option>
    | <wait_at_low_priority_option_list> , <wait_at_low_priority_option>
 
< wait_at_low_priority_option > ::=
    ABORT_AFTER_WAIT = { SELF | BLOCKERS }

注意

若要檢視 SQL Server 2014 與更早版本的 Transact-SQL 語法,請參閱舊版文件

引數

file_name

所要壓縮檔案的邏輯名稱。

file_id

所要壓縮檔案的識別碼 (ID)。 若要取得檔案識別碼,請使用 FILE_IDEX 系統函數或在目前的資料庫中查詢 sys.database_files 目錄檢視。

target_size

整數,代表檔案的新大小 (MB)。 若未指定或為 0,則 DBCC SHRINKFILE 會縮減成檔案建立大小。

您可以使用 DBCC SHRINKFILE <target_size> 縮減空白檔案的預設大小。 例如,如果建立 5 MB 的檔案,然後再將檔案縮減為 3 MB 且檔案仍維持空白,則預設的檔案大小會設定為 3 MB。 這僅適用於從未包含過資料的空白檔案。

FILESTREAM 檔案群組容器不支援此選項。

如果已指定,DBCC SHRINKFILE 會嘗試將檔案壓縮成 target_size。 檔案所要釋出區域中所使用頁面會移至檔案保留區域中的可用空間。 例如,有 10 MB 的資料檔案時,target_size 為 8 的 DBCC SHRINKFILE 作業會將檔案最後 2 MB 中所有已使用的頁面移入檔案前 8 MB 中任何未配置的頁面。 DBCC SHRINKFILE 壓縮檔案的程度,不會超過需要儲存的資料大小。 例如,如果使用了 10 MB 資料檔案中的 7 MB,將 DBCC SHRINKFILEtarget_size 設為 6 的 陳述式,只會將檔案壓縮成 7 MB,而不是 6 MB。

EMPTYFILE

將指定檔案中的所有資料移轉到「相同檔案群組」的其他檔案中。 換言之,EMPTYFILE 會將指定檔案中資料移轉至同一檔案群組中的其他檔案。 儘管不是唯讀檔案,EMPTYFILE 也可確保不會有任何新資料新增該檔案中。 您可以使用 ALTER DATABASE 陳述式來移除檔案。 如果您使用 ALTER DATABASE 陳述式來變更檔案大小,則唯讀旗標會重設,即可新增資料。

若是 FILESTREAM 檔案群組容器,在 FILESTREAM 記憶體回收行程執行並刪除所有由 EMPTYFILE 複製至其他容器且不再需要的檔案群組容器檔案之前,您無法使用 ALTER DATABASE 來移除檔案。 如需詳細資訊,請參閱 sp_filestream_force_garbage_collection。 如需移除 FILESTREAM 容器的詳細資訊,請參閱 ALTER DATABASE 檔案和檔案群組選項 (Transact-SQL) 中對應的章節

NOTRUNCATE

在有指定或未指定 target_percent 的情況下,將所配置頁面從資料檔案結尾移到檔案前面未配置的頁面。 檔案結尾的可用空間並不會歸還給作業系統,檔案的實際大小也不會改變。 因此,如果指定了 NOTRUNCATE,檔案不會呈現壓縮狀態。

NOTRUNCATE 只適用於資料檔案。 記錄檔不受影響。

FILESTREAM 檔案群組容器不支援此選項。

TRUNCATEONLY

將檔案結尾的所有可用空間釋出給作業系統,但是不會在檔案內移動任何頁面。 資料檔案只會壓縮為最後配置的範圍。

如果指定了 TRUNCATEONLY,則會忽略 target_size

TRUNCATEONLY 選項不會移動記錄檔中的資訊,但會移除記錄檔結尾非使用中的 VLF。 FILESTREAM 檔案群組容器不支援此選項。

WITH NO_INFOMSGS

隱藏所有參考訊息。

壓縮作業的 WAIT_AT_LOW_PRIORITY

適用於:SQL Server 2022 (16.x) 和更新版本、Azure SQL Database、Azure SQL 受控執行個體

低優先順序等候功能可減少鎖定競爭。 如需詳細資訊,請參閱了解 DBCC SHRINKDATABASE 的並行問題

這項功能與 WAIT_AT_LOW_PRIORITY 搭配線上索引作業類似,但是有些差異。

  • 您無法指定 ABORT_AFTER_WAIT 選項 NONE。

WAIT_AT_LOW_PRIORITY

適用於:SQL Server (SQL Server 2022 (16.x) 和更新版本) 及 Azure SQL Database。

在 WAIT_AT_LOW_PRIORITY 模式中執行壓縮命令時,等候壓縮作業會阻擋需要結構描述穩定性 (Sch-S) 鎖定的新查詢,直到壓縮作業停止等候並開始執行為止。 壓縮作業會在能夠取得結構描述修改鎖定 (Sch-M) 時執行鎖定。 如果 WAIT_AT_LOW_PRIORITY 模式中的新壓縮作業因長時間執行的查詢而無法取得鎖定,壓縮作業最終會在預設的 1 分鐘後逾時,結束時不發出通知。

如果 WAIT_AT_LOW_PRIORITY 模式中的新壓縮作業因長時間執行的查詢而無法取得鎖定,壓縮作業最終會在預設的 1 分鐘後逾時,結束時不發出通知。 如果壓縮作業因為並行的查詢或占用 Sch-S 鎖定的查詢而無法取得 Sch-M 鎖定,就會發生這種情況。 發生逾時的時候,錯誤 49516 訊息會傳送至 SQL Server 錯誤記錄檔,例如:Msg 49516, Level 16, State 1, Line 134 Shrink timeout waiting to acquire schema modify lock in WLP mode to process IAM pageID 1:2865 on database ID 5。 此時,您可以在 WAIT_AT_LOW_PRIORITY 模式中重試壓縮作業,並且知道不會對應用程式造成任何影響。

ABORT_AFTER_WAIT = [ SELF | BLOCKERS ]

適用於:SQL Server (SQL Server 2022 (16.x) 和更新版本) 及 Azure SQL Database。

  • SELF

    結束目前正在執行的壓縮檔案作業,但不採取任何動作。

  • BLOCKERS

    終止阻擋壓縮檔案作業的所有使用者交易,讓作業可以繼續。 BLOCKERS 選項需要登入才能擁有 ALTER ANY CONNECTION 權限。

結果集

下表會描述結果集資料行。

資料行名稱 描述
DbId 資料庫引擎嘗試壓縮之檔案的資料庫識別碼。
FileId 資料庫引擎嘗試壓縮之檔案的檔案識別碼。
CurrentSize 檔案目前所佔的 8 KB 頁數。
MinimumSize 檔案所能佔用的 8 KB 頁數最小值。 此數字對應於檔案大小下限或最初建立的大小。
UsedPages 檔案目前所用的 8 KB 頁數。
EstimatedPages 資料庫引擎估計檔案可以壓縮成 8 KB 頁面的頁數。

備註

DBCC SHRINKFILE 適用於目前資料庫的檔案。 如需如何變更目前資料庫的詳細資訊,請參閱 USE (Transact-SQL)

您可以隨時停止 DBCC SHRINKFILE 作業,任何已完成的工作都會保留下來。 如果您使用 EMPTYFILE 參數並取消作業,則不會標示檔案來防止新增額外的資料。

DBCC SHRINKFILE 作業失敗時,會引發錯誤。

在檔案壓縮期間,其他使用者也可操作資料庫;資料庫不一定要處於單一使用者模式。 您不需要為了壓縮系統資料庫,在單一使用者模式中執行 SQL Server 執行個體。

若指定了 WAIT_AT_LOW_PRIORITY,壓縮作業的 Sch-M 鎖定要求會在執行命令時,以低優先順序等候 1 分鐘。 如果作業被阻擋的時間達到該持續時間,則會執行指定的 ABORT_AFTER_WAIT 動作。

了解 DBCC SHRINKFILE 的並行問題

壓縮資料庫和壓縮檔案命令會導致並行問題,特別是使用中維護,例如重建索引或忙碌 OLTP 環境。 當您的應用程式對資料庫資料表執行查詢時,這些查詢會取得和維護結構描述穩定性鎖定 (Sch-S) 直到查詢完成其作業為止。 嘗試在一般使用期間回收空間時,壓縮資料庫和壓縮檔案作業目前會在移動或刪除索引配置對應 (IAM) 頁面時,要求結構描述修改鎖定 (Sch-M),從而阻擋使用者查詢需要的 Sch-S 鎖定。 因此,長時間執行的查詢會阻擋壓縮作業,直到查詢完成為止。 這表示任何需要 Sch-S 鎖定的新查詢也會排入等候壓縮作業後方的佇列,而且也會遭到阻擋,進一步讓並行問題惡化。 這可能會影響應用程式查詢效能,也會導致難以完成必要的維護來壓縮資料庫檔案。 壓縮在低優先順序等候的功能在 SQL Server 2022 (16.x) 推出,藉由讓結構描述修改鎖定進入 WAIT_AT_LOW_PRIORITY 模式,來解決此問題。 如需詳細資訊,請參閱在壓縮作業使用 WAIT_AT_LOW_PRIORITY

如需 Sch-S 和 Sch-M 鎖定的詳細資訊,請參閱交易鎖定和資料列版本設定指南

壓縮記錄檔

若是記錄檔,資料庫引擎會使用 target_size 來計算整份記錄的目標大小。 因此,target_size 是壓縮作業之後的記錄檔可用空間。 之後,便會將整份記錄之目標大小轉換成每個記錄檔的目標大小。 DBCC SHRINKFILE 會試圖將每個實體記錄檔立即壓縮成目標大小。 不過,如果有部分邏輯記錄位在超出目標大小的虛擬記錄中,資料庫引擎會盡可能釋出空間,然後發出一則參考用訊息。 這個訊息描述將邏輯記錄移出檔案結尾的虛擬記錄,需要哪些動作。 執行這些動作之後,就可以利用 DBCC SHRINKFILE 來釋出其餘空間。

由於記錄檔只能壓縮成虛擬記錄檔界限,因此可能無法將記錄檔壓縮成小於虛擬記錄檔的大小,即使它不在使用中也是如此。 建立或擴充記錄檔時,資料庫引擎會以動態方式選擇虛擬記錄檔大小。

最佳作法

當您計畫壓縮檔案時,請考量下列資訊:

  • 壓縮作業在截斷資料表或卸除資料表作業等建立大量未用空間的作業之後最有效。

  • 大部分資料庫都需要一些可用空間來執行每天的例行作業。 如果您反覆壓縮資料庫檔案,發現資料庫再次增長,就表示例行作業需要可用空間。 在這些情況之下,反覆壓縮資料庫檔案是一項會造成浪費的作業。 資料庫檔案成長所需的自動成長事件會阻礙效能。

  • 壓縮作業不會保留資料庫中索引的片段狀態,它通常會使片段增加到某個程度。 此片段就是不要反覆壓縮資料庫的另一個原因。

  • 循序而不是同時壓縮相同資料庫中的多個檔案。 系統資料表上的競爭可能會造成封鎖,因而導致延遲。

疑難排解

此章節描述如何診斷和更正在執行 DBCC SHRINKFILE 命令時可能發生的問題。

檔案未壓縮

如果在無錯誤壓縮作業之後檔案大小不會變更,請嘗試下列命令來確認檔案具有足夠的可用空間:

  • 執行下列查詢。
SELECT name
    , size / 128.0 - CAST(FILEPROPERTY(name, 'SpaceUsed') AS INT) / 128.0 AS AvailableSpaceInMB
FROM sys.database_files;
  • 執行 DBCC SQLPERF 命令會傳回交易記錄中所使用的空間。

如果可用的空間不足,壓縮作業無法更進一步地縮減檔案大小。

一般而言,呈現未壓縮狀態的都是記錄檔。 這種未壓縮狀態通常是因為記錄檔未遭截斷而造成。 若要截斷記錄檔,您可以將資料庫復原模式設定為 SIMPLE,或先備份記錄檔,然後再次執行 DBCC SHRINKFILE 作業。

壓縮作業遭到封鎖

以資料列版本設定為基礎的隔離等級下執行的交易可以封鎖壓縮作業。 例如,當 DBCC SHRINKDATABASE 作業執行時,如果正在以資料列版本設定為基礎的隔離等級下進行大量刪除作業,則壓縮作業會等到刪除作業完成之後再繼續。 發生此阻擋情形時,DBCC SHRINKFILEDBCC SHRINKDATABASE 作業會將參考用訊息 (若是 SHRINKDATABASE,為 5202;若是 SHRINKFILE,則為 5203) 列印到 SQL Server 錯誤記錄檔。 此訊息在第一個小時內每隔五分鐘記錄一次,然後每隔一小時記錄一次。 例如,如果錯誤記錄檔包含下列錯誤訊息,就會發生下列錯誤:

DBCC SHRINKFILE for file ID 1 is waiting for the snapshot
transaction with timestamp 15 and other snapshot transactions linked to
timestamp 15 or with timestamps older than 109 to finish.

此訊息表示時間戳記在 109 (壓縮作業所完成的最後一項交易) 之前的快照集交易將封鎖壓縮作業。 這也表示 sys.dm_tran_active_snapshot_database_transactions 動態管理檢視中的 transaction_sequence_numfirst_snapshot_sequence_num 資料行包含值 15。 如果 transaction_sequence_numfirst_snapshot_sequence_num 檢視資料行包含的數字小於壓縮作業最後完成的交易 (109),壓縮作業將會等到這些交易完成。

若要解決這個問題,可以執行下列其中一項工作:

  • 結束正在封鎖壓縮作業的交易。
  • 結束壓縮作業。 如果壓縮作業結束,則所有已完成的工作都會保留下來。
  • 不執行任何動作,並允許壓縮作業等到封鎖交易完成。

權限

需要 系統管理員 固定伺服器角色或 db_owner 固定資料庫角色中的成員資格。

範例

A. 將資料檔案壓縮為指定的目標大小

下列範例會將 UserDB 使用者資料庫中名為 DataFile1 之資料檔案大小壓縮成 7 MB。

USE UserDB;
GO
DBCC SHRINKFILE (DataFile1, 7);
GO

B. 將記錄檔壓縮為指定的目標大小

下列範例會將 AdventureWorks2022 資料庫中的記錄檔壓縮成 1 MB。 若要讓 DBCC SHRINKFILE 命令可以壓縮檔案,必須先將資料庫復原模式設定為 SIMPLE 以截斷檔案。

USE AdventureWorks2022;
GO
-- Truncate the log by changing the database recovery model to SIMPLE.
ALTER DATABASE AdventureWorks2022
SET RECOVERY SIMPLE;
GO
-- Shrink the truncated log file to 1 MB.
DBCC SHRINKFILE (AdventureWorks2022_Log, 1);
GO
-- Reset the database recovery model.
ALTER DATABASE AdventureWorks2022
SET RECOVERY FULL;
GO

C. 截斷資料檔案

下列範例會截斷 AdventureWorks2022 資料庫中的主要資料檔案, 並查詢 sys.database_files 目錄檢視以取得資料檔案的 file_id

USE AdventureWorks2022;
GO
SELECT file_id, name
FROM sys.database_files;
GO
DBCC SHRINKFILE (1, TRUNCATEONLY);

D. 清空檔案

下列範例示範如何清空檔案,使其能夠從資料庫中移除。 基於此範例的目的,會先建立資料檔案並包含資料。

USE AdventureWorks2022;
GO
-- Create a data file and assume it contains data.
ALTER DATABASE AdventureWorks2022
ADD FILE (
    NAME = Test1data,
    FILENAME = 'C:\t1data.ndf',
    SIZE = 5MB
    );
GO
-- Empty the data file.
DBCC SHRINKFILE (Test1data, EMPTYFILE);
GO
-- Remove the data file from the database.
ALTER DATABASE AdventureWorks2022
REMOVE FILE Test1data;
GO

E. 使用 WAIT_AT_LOW_PRIORITY 壓縮資料庫檔案

下列範例會將目前使用者資料庫中的資料檔案大小壓縮成 1 MB。 系統會查詢 sys.database_files 目錄檢視,以取得資料檔案的 file_id,在此範例中為 file_id 5。 如果無法在一分鐘內取得鎖定,壓縮作業將會中止。

USE AdventureWorks2022;
GO

SELECT file_id, name
FROM sys.database_files;
GO

DBCC SHRINKFILE (5, 1) WITH WAIT_AT_LOW_PRIORITY (ABORT_AFTER_WAIT = SELF);

另請參閱

下一步