SQL Server 2008 釋放堆表空間


前些天我遇到一個問題,一個200Gb的庫,其中一個表大約2000W行數據,我刪除了其中約600W行數據。我想把刪除后未使用的空間騰出來。

按照以往的經驗,重建這個表上的聚集索引就可以了。可是這次表上只有一個非聚集主鍵索引如何釋放這個堆表未使用的空間

首先來模擬出我遇到的情況:

USE master
GO
CREATE DATABASE TEST;
GO
USE TEST 
GO 
--每一行占一個PAGE. 
CREATE TABLE tb_Test 
(
 id INT NOT NULL ,
 val CHAR(8000)
);
ALTER TABLE dbo.tb_Test
  ADD CONSTRAINT PK_tbTest_id PRIMARY KEY NONCLUSTERED (id);
GO
 
        
INSERT INTO dbo.tb_Test
        ( id, val )
VALUES  ( 1, REPLICATE('A',10)),( 2, REPLICATE('B',10)),
        ( 3, REPLICATE('C',10)),( 4, REPLICATE('D',10)),
        ( 5, REPLICATE('E',10)),( 6, REPLICATE('F',10)),
        ( 7, REPLICATE('E',10)),( 8, REPLICATE('F',10)),
        ( 9, REPLICATE('E',10)),( 10, REPLICATE('F',10));
GO
DBCC SHOWCONTIG('tb_Test');
GO

(10 行受影響)
DBCC SHOWCONTIG 正在掃描 'tb_Test' 表...
表: 'tb_Test' (85575343);索引 ID: 0,數據庫 ID: 12
已執行 TABLE 級別的掃描。
- 掃描頁數................................: 10
- 掃描區數..............................: 5
- 區切換次數..............................: 4
- 每個區的平均頁數........................: 2.0
- 掃描密度 [最佳計數:實際計數].......: 40.00% [2:5]
- 區掃描碎片 ..................: 80.00%
- 每頁的平均可用字節數.....................: 83.0
- 平均頁密度(滿).....................: 98.97%

 

每行占用一個頁所以共有10頁,接下來我刪除其它5行。

DELETE FROM dbo.tb_Test
WHERE id<6;
GO 
DBCC SHOWCONTIG('tb_Test');
GO

(5 行受影響)
DBCC SHOWCONTIG 正在掃描 'tb_Test' 表...
表: 'tb_Test' (85575343);索引 ID: 0,數據庫 ID: 12
已執行 TABLE 級別的掃描。
- 掃描頁數................................: 10
- 掃描區數..............................: 5
- 區切換次數..............................: 4
- 每個區的平均頁數........................: 2.0
- 掃描密度 [最佳計數:實際計數].......: 40.00% [2:5]
- 區掃描碎片 ..................: 80.00%
- 每頁的平均可用字節數.....................: 4088.5
- 平均頁密度(滿).....................: 49.49%

 

仍然占用10頁,怎么釋放出這“空余”的5頁?

嘗試1:把非聚集主鍵索引改成聚集,再把它改回來。因為聚集索引的葉級頁是數據本身,所以創建或者重建都會重新組織數據頁。

ALTER TABLE [dbo].[tb_Test] DROP CONSTRAINT [PK_tbTest_id];
ALTER TABLE dbo.tb_Test
  ADD CONSTRAINT PK_tbTest_id PRIMARY KEY CLUSTERED (id);
ALTER TABLE [dbo].[tb_Test] DROP CONSTRAINT [PK_tbTest_id];
ALTER TABLE dbo.tb_Test
  ADD CONSTRAINT PK_tbTest_id PRIMARY KEY NONCLUSTERED (id);
GO 
DBCC SHOWCONTIG('tb_Test');
GO

DBCC SHOWCONTIG 正在掃描 'tb_Test' 表...
表: 'tb_Test' (85575343);索引 ID: 0,數據庫 ID: 12
已執行 TABLE 級別的掃描。
- 掃描頁數................................: 5
- 掃描區數..............................: 3
- 區切換次數..............................: 2
- 每個區的平均頁數........................: 1.7
- 掃描密度 [最佳計數:實際計數].......: 33.33% [1:3]
- 區掃描碎片 ..................: 66.67%
- 每頁的平均可用字節數.....................: 83.0
- 平均頁密度(滿).....................: 98.97%

這種做法有效。但是釋放出來的空間不會返還給OS,只是成為數據庫的Unused space.

嘗試2:收縮數據文件。無論是SHRINKDATABASE或是SHRINKFILE原理都是一樣的。執行下面查詢時,要回滾“嘗試1”的操作。

DBCC SHRINKFILE(TEST);
DBCC SHOWCONTIG('tb_Test');
GO

DBCC SHOWCONTIG 正在掃描 'tb_Test' 表...
表: 'tb_Test' (149575571);索引 ID: 0,數據庫 ID: 12
已執行 TABLE 級別的掃描。
- 掃描頁數................................: 5
- 掃描區數..............................: 3
- 區切換次數..............................: 2
- 每個區的平均頁數........................: 1.7
- 掃描密度 [最佳計數:實際計數].......: 33.33% [1:3]
- 區掃描碎片 ..................: 66.67%
- 每頁的平均可用字節數.....................: 83.0
- 平均頁密度(滿).....................: 98.97%

這種做法也有效,也可以根據Shrink的設定把空間返還給OS。但是在生產環境中,特別是較大的庫執行,影響特別大,容易產生大量碎片,一般不會用到。做為緊急應對的一種方法吧。

 

總結:

    1. 郁悶。我的生產環境中,在做了“嘗試1”並未起到效果,最后閑時維護使用“嘗試2”才釋放出來的。這點才是我做實驗和寫此文的初衷。

    2. 不管什么表,最好還是建立一個聚集索。利於管理使用空間,不然像5行數據占據10行的空間,這種事情會經常發生。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM