1

问题: 在 Sql server 2012 中,回收尽可能多的保留空间同时尽可能少的碎片的最佳方法是什么?

背景:

我们的 SQL 服务器磁盘空间不足,作为 HW+SW 升级的一部分,我们将把数据文件移动到不同的服务器——因此我们希望减小数据文件的大小(以防止不必要的“保留空间”移动。我们正在谈论泪珠)。我还想逐个分区执行此分区,以便能够在夜间运行并限制生产影响。

我尝试的一种方法(使用单个索引的重型消费者表上的每个分区):

ALTER TABLE <Tbl>
REBUILD PARTITION = <PartitionId> WITH (DATA_COMPRESSION =  PAGE) 
GO

--I know this is bad practice - but I need to reclaim space to speed up moving
DBCC SHRINKFILE(<PartitionName>, target_size = 10 )
GO

-- This is to mitigate the impact of shrinkfile
ALTER TABLE <Tbl>
REBUILD PARTITION = <PartitionId>
GO


--Run this in the end (and I run also between the individual tasks) to see impact on index fragmentation
SELECT * FROM sys.dm_db_index_physical_stats  
    (DB_ID(<DbName>), OBJECT_ID(<TblName>), <IndexId>, <PartitionId>, 'SAMPLED');  
GO

在测试环境中,这对某些分区产生了很好的结果(0% 的碎片化和保留空间上接近 0% 的“浪费”空间。考虑到下一阶段是通过线路移动数据而浪费了),但我有一个分区案例,SHRINKFILE 减少了大小显着,但会导致 99.99% 的碎片化;REBUILD 解决了碎片问题,但文件组大小加倍(一半是保留空间)——这可能是预期的,因为重建从头开始创建索引。如果我之后缩小,我可以回收空间,但会再次获得大碎片。这可以绕圈子

我现在正在尝试对缩小的文件组运行重组:

ALTER INDEX <IdxName> on <Tbl> REORGANIZE PARTITION = <PartitionId> 

因为这应该有望在不增加数据文件的情况下修复索引碎片。然而:

  • 在 99.99% 的碎片索引上运行 Reorganize 是个好主意吗?
  • 结果会与运行重建相当/劣于/优于吗?

我正在考虑的另一个选择是将分区重建为全新的文件组,但这需要操作分区模式 - 我希望使过程尽可能简单。

4

3 回答 3

1

如何使用压缩备份数据库并将其还原到新服务器。备份不包括未使用的空间。

于 2016-06-21T09:15:10.387 回答
1

这不是最好的答案,但这是我所做的,因为它最好地解决了我的具体情况——尤其是没有任何额外的可用空间可供使用——所以我什至不能使用备份-恢复方法;以及以较小(隔夜)批量执行操作的能力

我想发布它以防有人发现它有帮助。

但是- 最好确保您始终拥有至少与您的数据库当前占用的空间一样多的可用空间,然后您可以使用更合适的解决方案,例如我标记为答案的压缩备份建议。

--This is just so that anything doesn't interract with table during the entire process.
-- reorganize is being done online; but I want the process to finish as fast as possible and
--  app logic is resilient to not seeing the table for while
exec sp_rename  <tbl_orig>, <tbl>
GO

print 'starting compressing: ' + CAST(GETDATE() AS NVARCHAR)
GO

-- this is to enable compression on the partition
ALTER TABLE <tbl> 
REBUILD PARTITION = <PartitionId> WITH (DATA_COMPRESSION =  PAGE) 
GO

print 'Compressing done: ' + CAST(GETDATE() AS NVARCHAR)
GO

-- recaliaming all free space; potentially very bad fragmentation is possible
DBCC SHRINKFILE(<DataFile>, target_size = 10 )
GO

print 'shrinking done: ' + CAST(GETDATE() AS NVARCHAR)
GO

-- solve the fragmentation without giving up on any reclaimed space. Rebuild would use some additional space.
-- This assumes that my partitions are stored in dedicated filegroups (which is always a good idea)
ALTER INDEX <IdxName> on <tbl> REORGANIZE PARTITION = <PartitionId>
GO

print 'index reorganizing done: ' + CAST(GETDATE() AS NVARCHAR)
GO

-- see the stats
SELECT * FROM sys.dm_db_index_physical_stats  
    (DB_ID(<DBName>), OBJECT_ID(<Tbl>), 1, <PartitionId> , 'SAMPLED');  
GO

print 'DONE: ' + CAST(GETDATE() AS NVARCHAR)
GO

-- show the table back to app logic
exec sp_rename  <tbl>, <tbl_orig>
GO
于 2016-06-22T09:54:32.260 回答
0

您可以将分区重建到新的文件组。这将产生完美连续的页面和完美填充的文件。这通常是一种非常好的碎片整理方法。您可以自动执行此操作。

正如您发现的那样,通过就地重建进行碎片整理存在一些问题。您需要大量临时空间,并且您新分配的 b-tree 将被 SQL Server 分配算法压缩成大量可用空间空洞。分配算法并不聪明。它不会试图找到大洞。如果存在的话,很高兴将新树铺在小洞上。这就是你在重建后可能会直接被碎片化的原因。(有趣的是,NTFS 也有同样的问题。如果你只是按顺序写入一个 100GB 的文件,它最终可能会非常碎片化。)

我相信这个问题在 SQL Server 社区中并没有被广泛理解。

于 2016-06-22T10:20:46.050 回答