表有 14 GB 的未使用空间 - 如何缩小表大小

web*_*orm 6 sql-server database-size azure-sql-database

我使用以下脚本从我的数据库中收集数据,即 Azure 上的 SQL Server。

-- Script to run against database to gather metrics

CREATE TABLE #SpaceUsed (name sysname,rows bigint,reserved sysname,data sysname,index_size sysname,unused sysname)

DECLARE @Counter int 
DECLARE @Max int 
DECLARE @Table sysname

SELECT  name, IDENTITY(int,1,1) ROWID 
INTO       #TableCollection 
FROM    sysobjects 
WHERE xtype = 'U' 
ORDER BY lower(name)

SET @Counter = 1 
SET @Max = (SELECT Max(ROWID) FROM #TableCollection)

WHILE (@Counter <= @Max) 
    BEGIN 
        SET @Table = (SELECT name FROM #TableCollection WHERE ROWID = @Counter) 
        INSERT INTO #SpaceUsed 
        EXECUTE sp_spaceused @Table 
        SET @Counter = @Counter + 1 
    END

SELECT * FROM #SpaceUsed

DROP TABLE #TableCollection 
DROP TABLE #SpaceUsed
Run Code Online (Sandbox Code Playgroud)

我的一张桌子是53 GB in size, 38 GB in data, 14 GB in unused。索引是11 MB in size. 我该如何收回那个14 GB that is unused?由于这是在 Azure 中,额外的空间需要花钱。

在阅读了各种文章后,我尝试了以下方法来减小表格的大小。

DBCC DBREINDEX ('myTableName', ' ')
DBCC SHRINKDATABASE (myDatabaseName, 10);
Run Code Online (Sandbox Code Playgroud)

但是,这些完成后,表的大小保持不变。如何减少表和数据库的大小以回收未使用的空间?

更新:表中有 24 列,其中 9 个字段是大长度 (> 4000) 或 varchar(MAX) 的 varchar。另外 8 列是唯一标识符类型。

Aar*_*and 12

无论是堆索引还是聚集索引,您都会发现可以通过重建来回收表中的空间:

ALTER INDEX ALL ON dbo.myTableName REBUILD;
Run Code Online (Sandbox Code Playgroud)

请注意,回收表中的空间和缩小数据库是两件完全独立的事情。缩小数据库应该是一件特殊的事情 - 不要仅仅为了释放磁盘空间而缩小数据库,因为在大多数情况下,数据库将不得不再次增长并再次使用该空间。

至于确定表的分布方式,sp_spaceused是非常无用的,因为它只为您提供一个包含所有数据的行项目。首先,检查您的表是否已分区。您可以使用以下命令快速查看:

SELECT COUNT(*)
  FROM sys.partitions
  WHERE partition_number > 1
  AND object_id = OBJECT_ID(N'dbo.myTableName');
Run Code Online (Sandbox Code Playgroud)

接下来,查看数据在您的七个索引中的布局。如果其中之一比应有的大很多,您可以尝试删除/重新创建(包括可能从INCLUDE列表中删除您的 XML 列),因为可能存在已删除行的 LOB 空间的情况或设置为NULL即使在重建后也不会完全恢复。

 ;WITH x AS
  ( 
    SELECT i.name, type = pa.allocation_unit_type_desc, kb = COUNT(*) * 8
    FROM sys.indexes AS i
    CROSS APPLY sys.dm_db_database_page_allocations(DB_ID(), i.object_id, i.index_id, 
      NULL, 'LIMITED') AS pa
    WHERE i.[object_id] = OBJECT_ID(N'dbo.myTableName')
    GROUP BY GROUPING SETS((), (i.name, pa.allocation_unit_type_desc))
  )
  SELECT name, type, kb, 
    [%] = CONVERT(decimal(5,2), kb*100.0/(SELECT kb FROM x WHERE name IS NULL))
    FROM x
    WHERE name IS NOT NULL
    ORDER BY name, type;
Run Code Online (Sandbox Code Playgroud)

如果要查看基表中的单个行大小,可以执行以下操作:

SELECT TOP (100) key, rowsize = DATALENGTH(col1) + DATALENGTH(col2) + ...
  FROM dbo.myTableName
  ORDER BY rowsize DESC;
Run Code Online (Sandbox Code Playgroud)

如果您有一些非常大的数据,您可能需要确保需要该数据(否则将其设置为NULL,因为它可能会影响您的大小。