[SQL][問題處理]資料表在每個資料檔案各占用多少空間

[SQL][問題處理]資料表在每個資料檔案各占用多少空間

臨時遇到一個狀況,原本在某台 SQL Server 主機上因為有一些 I/O 瓶頸,因此協助設定了 Instance 參數,調整「平行處理原則的成本臨界值」和「平行處理原則的最大程度」,並且將大量 I/O 的資料庫增加三個 NDF,並且重建 Cluster Index,讓資料可以平均存放。看起來是個很單純的處理,因此花了一些時間監控和測試,取得較適合的參數值之後,就協助客戶做好設定了。

 

這樣的處理經過一兩週的測試之後,效果看起來還算不錯,都有達到預期改善的目標,就要在結案收款的時候,客戶忽然出了一個難題,要我們證明資料表內的資料都有平均散放在這些資料表內。這就有點頭痛了,就以往所知道的,可以透過一些系統檢視,像是 sys.indexes 去取得在每個 Partition 下面的 rows 和 pages,似乎沒有辦法知道在每個檔案上各占用多少,要怎麼要來知道呢 ?

 

就在百思不得其解的時候,百敬老師提醒了一段「要能呈現 page id 的分布」,讓我忽然被點醒了,想到可以利用 「DBCC IND」來處理,因此就寫了以下的程式碼

-- 建立暫存資料表
CREATE TABLE #DBCCIND 
(
    PageFID  INT,
    PagePID  INT,
    IAMFID   INT,
    IAMPDF   INT,
    ObjectID INT,
    IndexID  INT,
    PartitionNumber INT,
    PartitionID  BIGINT,
    iam_chain_type  SYSNAME,
    PageType    INT,
    IndexLevel  INT,
    NextPageFID INT,
    NextPagePID INT,
    PrevPageFID INT,
    PrevPagePID INT
)
GO
 
-- 利用 DBCC IND 將範例資料庫和資料表的資訊存放到暫存資料表內
INSERT INTO #DBCCIND
EXEC( 'DBCC IND("SampleDB",SampleTable, 1) WITH TABLERESULTS ')
GO
 
-- 取出資料頁的資訊做統計
SELECT PageFID,m.physical_name, COUNT(*)*8/1024.0 "Size" 
FROM #DBCCIND i
JOIN sys.master_files m ON m.database_id = DB_ID("SampleDB") AND m.file_id = i.PageFID
WHERE IndexID = 1 AND PageType = 1
GROUP BY PageFID,m.physical_name
ORDER BY PageFID

 

執行完之後就可以得到結果了

image

 

而在上述的語法中,大家比較陌生的應該是 DBCC IND,他前面兩個參數分別是資料庫和物件,第三個參數就有 –2,–1, 0 , 1 四種值可以使用,其中:

1   Cluster Index

0   所有的資料頁和 IAM ( Heap )

-1   所有的頁面資訊,包含 LOB ( Large Object Binary )

-2   所有的 IAM 資訊

 

由於我的範例資料表是有建立 Cluster Index,因此在上述的範例中,我在 DBCC IND 第三個參數填入參數 1 。而 DBCC IND 的結果中,我就取出所有的資料頁 ( PageType = 1 ) 的資訊,因為他是計算出有多少的 Page,因此我把結果 *8 / 1024.0,將他換算成為 MB。

 

由於這個狀況是在 SQL Server 2008,因此處理起來會比較麻煩一點。然而如果您的環境是 SQL Server 2012 以上,就不用那麼麻煩了,可以用另外一個新的 DMV 「sys.dm_db_database_page_allocations」來取代,因此可以更為簡化寫成如下的方式

-- 利用 DMV 來處理
select allocated_page_file_id,count(*)*8/1024.0 'Size' , m.physical_name
from sys.dm_db_database_page_allocations( DB_ID('SampleDB'), OBJECT_ID('SampleTable'),1, NULL,NULL) a
join sys.master_files m ON a.database_id = m.database_id AND a.allocated_page_file_id = m.file_id
group by allocated_page_file_id,m.physical_name
order by allocated_page_file_id

 

出來的結果是一樣的,但使用起來方便多了。如果大家對這些指令想了解的話,可以參考以下的網址,會有更詳細的說明。

 

參考資料

1. More undocumented fun: DBCC IND, DBCC PAGE, and off-row columns

2. A REPLACEMENT FOR DBCC IND IN SQL SERVER 2012