Sql-Server

sys.allocation_units 和 sp_spaceused 上的空間使用情況

  • September 4, 2018

眾所周知,DMV 不保存有關頁數和行數的準確資訊。但是,當您更新統計數據時,我看不出他們為什麼不這樣做。

我正在開發一個監控工具,想知道每個索引和數據的磁碟大小等。最終我想找到正確的填充因子,等等。

我的函式和舊的 sp_spaceused 使用的空間在空間使用方面略有不同,但在記錄數上沒有區別。

你能看看我的選擇中是否缺少任何東西嗎?

這是 sp_spaceused (然後我將數字轉換為 MB):

sp_spaceused 'tblBOrderRelationship'
go

select 318008/1024.00 AS reserved,
140208/1024.00  AS data,
177048/1024.00 AS index_size,
752/1024.00    AS unused

在此處輸入圖像描述

但是當我執行我的選擇,下面的程式碼\下面的圖片時,我得到的數字略有不同。

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT 
   schema_name(t.schema_id) as SchemaName,
   t.NAME AS TableName,
   t.type_desc,
   t.is_ms_shipped,
   t.is_published,
   t.lob_data_space_id,
   t.filestream_data_space_id,
   t.is_replicated,
   t.has_replication_filter,
   t.is_merge_published,
   t.is_sync_tran_subscribed,
   --t.is_filetable,
   i.name as indexName,
   i.type_desc,
   i.is_unique,
   i.is_primary_key,
   i.is_unique_constraint,
   i.fill_factor,
   i.is_padded,


   sum(p.rows)               OVER (PARTITION BY t.OBJECT_ID,i.index_id)  as RowCounts,
   sum(a.total_pages)        OVER (PARTITION BY t.OBJECT_ID,i.index_id)  as TotalPages, 
   sum(a.used_pages)         OVER (PARTITION BY t.OBJECT_ID,i.index_id)  as UsedPages, 
   sum(a.data_pages)         OVER (PARTITION BY t.OBJECT_ID,i.index_id)  as DataPages,

   (sum(a.total_pages)       OVER (PARTITION BY t.OBJECT_ID,i.index_id)  * 8) / 1024 as TotalSpaceMB, 
   (sum(a.used_pages)        OVER (PARTITION BY t.OBJECT_ID,i.index_id)  * 8) / 1024 as UsedSpaceMB, 
   (sum(a.data_pages)        OVER (PARTITION BY t.OBJECT_ID,i.index_id)  * 8) / 1024 as DataSpaceMB
FROM 
   sys.tables t
INNER JOIN      
   sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN 
   sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN 
   sys.allocation_units a ON p.partition_id = a.container_id
WHERE 
   t.NAME NOT LIKE 'dt%' AND
   i.OBJECT_ID > 255 
AND T.NAME = 'tblBOrderRelationship'

數字

數字

更大的圖景,包括索引名稱 更大的圖景,包括索引名稱

現在做一些計算來檢查結果:

--==================================
-- the figures from sp_spaceused
--==================================
select 318008/1024.00 AS reserved,
140208/1024.00  AS data,
177048/1024.00 AS index_size,
752/1024.00    AS unused

--==================================
-- the figures from my select
--==================================
select 137+61+56+54 AS reserved,
      137 AS data,
      61+56+54 AS index_size

在此處輸入圖像描述

除了我沒有計算未使用的空間之外,它並沒有那麼遠,真的!

我該怎麼做才能使這個準確?

更改後:

在我將 1024 替換為 1024.00 之後,結果更加準確。我注意到記錄已插入到有問題的表中,顯然統計數據不是最新的,但結果仍然匹配(低於 1 MB 差異 - 這對我來說沒問題)

新的結果集是:

--==================================
-- the figures from sp_spaceused
--==================================
select
318072 /1024.00 AS reserved,
140208 /1024.00 AS data,
177096 /1024.00 AS index_size,
768 /1024.00 AS unused
go

--==================================
-- the figures from my select
--==================================
select 137.7578125+61.7968750+56.4218750+54.6406250 as reserved,
      137.7578125 as data,
      61.7968750+56.4218750+54.6406250 as index_size

在此處輸入圖像描述

即使您修復了直接舍入問題,獲取每個對象/索引統計資訊的整體算法也是不正確的。它不能正確處理 LOB 和行溢出數據。它還排除:索引視圖、全文索引、XML 索引和其他一些情況。因此,您可能看不到所有數據。

以下是我在 StackOverflow 上發布的答案(sp_spaceused - 如何測量 SQL 中所有表中的 GB 大小)的程式碼的改編,它處理了所有處理的情況sp_spaceused。這個 SO 問題只涉及每個對象的統計資訊,而不是每個索引,所以我調整了程式碼以處理索引級別的事情。

;WITH agg AS
(   -- Get info for Tables, Indexed Views, etc
   SELECT  ps.[object_id] AS [ObjectID],
           ps.index_id AS [IndexID],
           NULL AS [ParentIndexID],
           NULL AS [PassThroughIndexName],
           NULL AS [PassThroughIndexType],
           SUM(ps.in_row_data_page_count) AS [InRowDataPageCount],
           SUM(ps.used_page_count) AS [UsedPageCount],
           SUM(ps.reserved_page_count) AS [ReservedPageCount],
           SUM(ps.row_count) AS [RowCount],
           SUM(ps.lob_used_page_count + ps.row_overflow_used_page_count)
                   AS [LobAndRowOverflowUsedPageCount]
   FROM    sys.dm_db_partition_stats ps
   GROUP BY    ps.[object_id],
               ps.[index_id]
   UNION ALL
   -- Get info for FullText indexes, XML indexes, Spatial indexes, etc
   SELECT  sit.[parent_id] AS [ObjectID],
           sit.[object_id] AS [IndexID],
           sit.[parent_minor_id] AS [ParentIndexID],
           sit.[name] AS [PassThroughIndexName],
           sit.[internal_type_desc] AS [PassThroughIndexType],
           0 AS [InRowDataPageCount],
           SUM(ps.used_page_count) AS [UsedPageCount],
           SUM(ps.reserved_page_count) AS [ReservedPageCount],
           0 AS [RowCount],
           0 AS [LobAndRowOverflowUsedPageCount]
   FROM    sys.dm_db_partition_stats ps
   INNER JOIN  sys.internal_tables sit
           ON  sit.[object_id] = ps.[object_id]
   WHERE   sit.internal_type IN
              (202, 204, 207, 211, 212, 213, 214, 215, 216, 221, 222, 236)
   GROUP BY    sit.[parent_id],
               sit.[object_id],
               sit.[parent_minor_id],
               sit.[name],
               sit.[internal_type_desc]
), spaceused AS
(
SELECT  agg.[ObjectID],
       agg.[IndexID],
       agg.[ParentIndexID],
       agg.[PassThroughIndexName],
       agg.[PassThroughIndexType],
       OBJECT_SCHEMA_NAME(agg.[ObjectID]) AS [SchemaName],
       OBJECT_NAME(agg.[ObjectID]) AS [TableName],
       SUM(CASE
               WHEN (agg.IndexID < 2) THEN agg.[RowCount]
               ELSE 0
           END) AS [Rows],
       SUM(agg.ReservedPageCount) * 8 AS [ReservedKB],
       SUM(agg.LobAndRowOverflowUsedPageCount +
           CASE
               WHEN (agg.IndexID < 2) THEN (agg.InRowDataPageCount)
               ELSE 0
           END) * 8 AS [DataKB],
       SUM(agg.UsedPageCount - agg.LobAndRowOverflowUsedPageCount -
           CASE
               WHEN (agg.IndexID < 2) THEN agg.InRowDataPageCount
               ELSE 0
           END) * 8 AS [IndexKB],
       SUM(agg.ReservedPageCount - agg.UsedPageCount) * 8 AS [UnusedKB],
       SUM(agg.UsedPageCount) * 8 AS [UsedKB]
FROM    agg
GROUP BY    agg.[ObjectID],
           agg.[IndexID],
           agg.[ParentIndexID],
           agg.[PassThroughIndexName],
           agg.[PassThroughIndexType],
           OBJECT_SCHEMA_NAME(agg.[ObjectID]),
           OBJECT_NAME(agg.[ObjectID])
)
SELECT sp.SchemaName,
      sp.TableName,
      sp.IndexID,
      CASE
        WHEN (sp.IndexID > 0) THEN COALESCE(si.[name], sp.[PassThroughIndexName])
        ELSE N'<Heap>'
      END AS [IndexName],
      sp.[PassThroughIndexName] AS [InternalTableName],
      sp.[Rows],
      sp.ReservedKB,
      (sp.ReservedKB / 1024.0 / 1024.0) AS [ReservedGB],
      sp.DataKB,
      (sp.DataKB / 1024.0 / 1024.0) AS [DataGB],
      sp.IndexKB,
      (sp.IndexKB / 1024.0 / 1024.0) AS [IndexGB],
      sp.UsedKB AS [UsedKB],
      (sp.UsedKB / 1024.0 / 1024.0) AS [UsedGB],
      sp.UnusedKB,
      (sp.UnusedKB / 1024.0 / 1024.0) AS [UnusedGB],
      so.[type_desc] AS [ObjectType],
      COALESCE(si.type_desc, sp.[PassThroughIndexType]) AS [IndexPrimaryType],
      sp.[PassThroughIndexType] AS [IndexSecondaryType],
      SCHEMA_ID(sp.[SchemaName]) AS [SchemaID],
      sp.ObjectID
      --,sp.ParentIndexID
FROM   spaceused sp
INNER JOIN sys.all_objects so -- in case "WHERE so.is_ms_shipped = 0" is removed
       ON so.[object_id] = sp.ObjectID
LEFT JOIN  sys.indexes si
      ON  si.[object_id] = sp.ObjectID
     AND  (si.[index_id] = sp.IndexID
        OR si.[index_id] = sp.[ParentIndexID])
WHERE so.is_ms_shipped = 0
--so.[name] LIKE N''  -- optional name filter
--ORDER BY ????

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