释放未使用的空间SQL Server表


11

我在SQL Server 2012 Express中有一个表,其中有很多未使用的空间。

我需要释放数据库中的空间。

| NAME | 行| 保留 数据| INDEX_SIZE | 未使用
| ------------- | -------- | -------------- | ----------- --- | ------------ || -------------- |
| MyTableName | 158890 | 8928296 KB | 5760944 KB | 2248 KB | 3165104 KB |

如何获得SQL释放3165104KB?

我已经尝试过:

Alter table MyTableName Rebuild
DBCC CLEANTABLE (MyDbName,"MyTableName ", 0)
ALTER INDEX ALL ON MyTableName REORGANIZE ; 
ALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF) 

表格如下:

CREATE TABLE [dbo].[MyTableName](
    [ImageID] [int] IDENTITY(1,1) NOT NULL,
    [DateScan] [datetime] NULL,
    [ScanImage] [image] NULL,
 CONSTRAINT [PK_Image] PRIMARY KEY CLUSTERED 
(
    [ImageID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
    ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

我们唯一要做的是ScanImage在每行上替换一个较小的图像(这是有那么多未使用空间的地方)。

Answers:


10

我们唯一要做的是ScanImage在每一行上替换一个较小的图像(这就是有那么多未使用空间)

通过进行一些试验,最节省空间的方法是删除分配单元并重新填充它(如果您有维护窗口可以这样做)。

使用问题中的表结构为我实现最佳空间缩减的示例代码是:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

SET XACT_ABORT ON;

BEGIN TRAN

SELECT [ImageID],
       [ScanImage]
INTO   #Temp
FROM   [dbo].[MyTableName]

ALTER TABLE [dbo].[MyTableName]
  DROP COLUMN [ScanImage]

/*Allocation unit not removed until after this*/
ALTER INDEX PK_Image ON MyTableName REBUILD

ALTER TABLE [dbo].[MyTableName]
  ADD [ScanImage] IMAGE NULL

UPDATE [dbo].[MyTableName]
SET    [ScanImage] = T.[ScanImage]
FROM   [dbo].[MyTableName] M
       JOIN #Temp T
         ON M.ImageID = T.[ImageID]

DROP TABLE #Temp

COMMIT 

一切都在事务中,因此如果计算机崩溃,它将回滚。可能至少可以处理一些错误SET XACT_ABORT ON。我曾经SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;防止在复制期间或复制之后发生任何并发修改而丢失它们。

减小image所有行的大小后,保留的LOB页数如下:

+ ------------------------------------------------- -+ --------------------- + ------------------------- +
| 大事记 lob_used_pa​​ge_count | lob_reserved_pa​​ge_count |
+ ------------------------------------------------- -+ --------------------- + ------------------------- +
| 插入10,000行,每个行有100,000字节数据| 135005 | 135017 |
| 将所有行更新为10,000字节的图像数据| 31251 | 135012 |
| 重组| 23687 | 25629 |
| 拖放并重新添加图像数据| 13485 | 13489 |
+ ------------------------------------------------- -+ --------------------- + ------------------------- +

1
或者,如果表很大,则在维护窗口期间BCP输出数据,然后BULK INSERT重新输入。
2013年

6

尝试

ALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF)

这将重新创建聚簇索引,因此您将需要数据库中有更多空间才能完成操作。如果由于磁盘已满而没有多余的空间,则可以将新的数据文件添加到数据库(在另一个磁盘上)并将表移至该数据库。

也有可能用小于100%的FILLFACTOR定义聚簇索引。将填充因子设置为例如66%,会将每个数据页的1/3留空以备将来使用。如果这是问题,您可以使用ALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF, FILLFACTOR=100)

如果您最近从表中删除了一个可变长度字段,也可以尝试 DBCC CLEANTABLE( Databasename, "MyTableName")

在线图书(BOL)在http://technet.microsoft.com/zh-cn/library/ms188388%28v=sql.100%29.aspx上有一篇有关重建索引的精彩文章


2

确保数据库恢复模式为SIMPLE

将列更改为VARBINARY(MAX)

然后尝试将数据复制到一个全新的表中。

使用检查新表的大小sp_spaceused "tablename"。如果您对表的未使用空间感到满意,请使用相同的命令检查数据库的未使用空间,而不指定表名。该空间仍位于数据库文件中,并且不会释放到操作系统。

如果您不信任重命名操作(我不完全信任),则可以删除原始表并重命名新表,或者再次做同样的事情,并使用原始表名。

如果这可行,那么最后一步很容易:您知道如何缩小文件并释放未使用的空间。

如果有任何外键,请记录它们的定义,将其删除,执行上面提到的任务,然后再重新创建外键。当然,这将花费一些时间,并且该操作应在非工作时间进行。整个任务也可以通过脚本来完成,以使其能够在一夜之间运行。


1

我只是创建一个新数据库并将数据复制到该数据库。您应该可以使用导入/导出向导。(显然,备份和还原可以解决该问题。)检查导入数据的结果。如果一切正常,请重命名原始数据库,然后将新数据库重命名为您要使用的名称。(我总是会稍等片刻再放掉原件,只是为了进行在线仔细检查。)

为了它的价值,我们还通过以下步骤从数据库中回收了blob空间(如果它们不太大)。(但是,由于您使用的是SQL Server Express,因此您可能没有足够的空间尝试此操作。)

  1. 将新文件添加到文件组。
  2. 运行DBCC SHRINKFILE(file, EMPTYFILE)。由于您正在收缩MDF,因此最终将失败,因为无法移动系统元数据。但是,空的Blob分配不会移动。
  3. 运行DBCC SHRINKFILE(newfile,EMPTYFILE)。这会将数据移回去,减去多余的空间。
  4. 从文件组中删除新文件(现在为空)。

这消除了斑点膨胀。我应该提到,我们主要是使用这种技术来创建一个几乎为空的数据库来测试升级脚本。


-1

重新组织聚簇索引-索引在节点上有数据,因此....它很可能是零散的。


我尝试运行:ALTER INDEX ALL ON [MyTableName] REORGANIZE;
DermFrench

3
重建它;)不重新组织。
TomTom
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.