重建数据库失败,但数据库大小增加了一倍

the*_*nom 5 sql-server maintenance size restore index-rebuild

我尝试使用查询重建数据库的所有索引,

USE [DB_Name];
GO
DECLARE @TableName VARCHAR(255)
DECLARE @sql NVARCHAR(500)
DECLARE TableCursor CURSOR FOR
SELECT '['+OBJECT_SCHEMA_NAME([object_id])+']'+'.'+name AS TableName
FROM sys.tables
OPEN TableCursor
FETCH NEXT FROM TableCursor INTO @TableName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = 'ALTER INDEX ALL ON ' + @TableName + ' REBUILD'
PRINT @sql
EXEC (@sql)
FETCH NEXT FROM TableCursor INTO @TableName
END
CLOSE TableCursor
DEALLOCATE TableCursor
GO
Run Code Online (Sandbox Code Playgroud)

该查询执行了大约 3.5 小时,然后抛出错误消息,指出磁盘空间不足,这不是真的,但可能是数据库达到了其大小限制。

但唯一的问题是数据库的大小实际上增长了几乎 100%,而没有重建任何索引。我选择重建的主要原因是大多数索引碎片超过75%。

现在,不幸的是,从备份恢复不是一个选择,因为我们已经写入了新数据,而且已经过去了几个小时。

再次使用足够的磁盘空间进行重建可以解决问题吗?如果是这样,我是否仍然遵循当前数据库空间 1.5 倍的经验法则?

J.D*_*.D. 7

正如这些有关索引维护的 Microsoft 文档中所讨论的,这是索引重建的典型行为。Microsoft 建议至少保留两倍的可用空间,因为重建会存储与旧索引同时重建的索引的新副本。重建完成后,旧索引将被删除,但数据库文件在磁盘上仍将保持其增长时的大小。

请参阅链接文档中的以下内容:

当发生索引重建时,物理介质必须有足够的空间来存储索引的两个副本。重建完成后,数据库引擎将删除原始索引。

如果索引很大,重建整个表需要很长时间,并且在重建过程中需要足够的磁盘空间来存储整个索引的额外副本。

尽管有上述文档,但如今众所周知,行存储索引维护在实践中并不是一个有用的操作。无论索引的碎片程度如何,它很少能有效地提高数据库的性能。这是对 I/O 操作和磁盘空间的浪费(正如您所注意到的),而且事后几乎没有什么收获。如果您SHRINK随后更改数据库,则会导致索引再次重新碎片化,回到第 1 方,代价是额外的 I/O。索引维护中确实发生的后续操作(例如更新统计数据)可以单独运行,以便无需索引维护成本即可获得这些收益。

我个人只看到它对没有聚集索引的架构不佳的数据库有帮助,这意味着它们的数据一开始就是无序存储在堆中的。这些堆表及其非聚集索引碎片严重,索引维护确实有助于改善它们。但这是一种糟糕的数据库设计,任何人都不应该从一开始就进行架构设计。

最后,请参阅 AMTwo 的有用备忘单,了解何时重建索引


如果在完成所有这些之后,您仍然对索引维护感到困扰,那么也许您应该尝试重新组织索引。重组可以修复现有索引中的碎片,因此与重建索引相比,使用的操作空间要少得多。

  • 我制作了这个方便的花花公子备忘单,以帮助人们解决是否应该重建索引的问题。shouldirebuildindexes.com (5认同)