我需要缩小我的数据库 - 我刚刚释放了很多空间

Mik*_*lsh 36 sql-server shrink

这个问题在这里以各种形式提出,但问题归结为:

我知道缩小数据库是有风险的。在这种情况下,我已经删除了这么多数据,我再也不会使用它了。

  • 如何缩小我的数据库?我缩小了哪些文件?
  • 这样做时我应该考虑什么?
  • 之后我应该做些什么吗?
  • 如果是大数据库呢?我可以以较小的增量缩小它吗?

Mik*_*lsh 33

一些初始警告:

  1. 它通常被称为一个最坏的实践不断缩小生产数据库或数据文件(日志文件是另一个问题,因为这个问题挂在嘴边)。我建议人们不要在像这样的博客文章中缩小他们的数据库,在那里我谈论“适当的规模”和良好的规划。我并不孤单(Paul RandalBrent Ozar,只是为了提供更多链接)。收缩数据文件或数据库碎片索引,是缓慢而费力的在你的资源,可以为您的系统上的排水,只是一个坏的事情,一般
  2. 在这种情况下,我们都知道存在风险,我们已准备好应对它,但我们释放了很多我们知道永远不会再需要的空间。所以在这种特定类型的情况下 - 缩小作为我们的选择之一很有意义。

如果你读过有关的问题和风险,你仍然需要,因为你释放一个做到这一点的收缩显著的空间大小,这个答案的希望其余部分将帮助你。但一定要考虑风险。

这里有两种主要方法:

1.)收缩 是的,进行实际收缩- 考虑使用DBCC SHRINKFILE代替DBCC SHRINKDATABASE,您可以更好地控制收缩的内容和方式。这肯定导致一些性能下降 - 这是一个执行大量 IO 的大型操作。你可以潜在地逃脱反复收缩到渐进地小的目标大小。

这是上面DBCC SHRINKFILE链接中的“A.)”示例。在此示例中,数据文件被缩小到 7MB 目标大小。这种格式是在停机时间窗口允许的情况下反复收缩的好方法。我会在开发测试中这样做,以查看性能如何以及增量的低/高,并确定生产中的预期时间。这是一个在线操作——你可以在系统中的用户访问被收缩的数据库的情况下运行它,但会出现性能下降,几乎可以保证。因此,监视和观察并查看您对服务器进行的操作,最好选择停机时间窗口或活动较少的时段。

USE YourDatabase;
GO
DBCC SHRINKFILE (DataFile1, 7);
GO
Run Code Online (Sandbox Code Playgroud)

永远记住: - 每次收缩都会使索引碎片化,如果要在很长一段时间内成块地收缩,应该重建索引。如果您无法在一个窗口中完成所有工作,您现在每次都会产生这笔费用。

2.)新数据库- 您可以创建一个新数据库并将数据迁移到其中。您必须编写空数据库及其所有键、索引、对象、过程、函数等的脚本,然后将数据迁移到其中。您可以为此编写脚本,也可以使用 Red Gate 的 SQL Data Compare 或其他具有类似工具的供应商之类的工具。这对你来说是更多的设置工作,更多的开发和测试,并且根据你的环境也可能会破坏你的停机时间,但也是一个可以考虑的选择。

当我被迫缩小数据库时 如果这是我的环境,我希望在数据文件中留下相当/大量的空白,因为我喜欢成为一个磁盘猪,并且喜欢为未来/意外的增长做好准备。因此,如果我们只是删除大部分空间,我可以回馈空间,但我永远不会相信那些说“但它永远不会再增长”并且仍然留下一些空白的人。我可能会走的路线(叹气) 是收缩方法,如果我有较小的停机时间窗口并且不想招致创建空数据库并将数据迁移到它的复杂性。所以我会逐渐缩小它很多次(基于我认为我需要多少次基于我在开发中的测试和所需的大小。逐渐选择一个较小的文件大小)然后重建索引..然后我'永远不要告诉任何人我缩小了我的数据库;-)


Csa*_*oth 5

  1. 如何缩小我的数据库?我缩小了哪些文件?:您可以通过DBCC SHRINKFILE您提到的命令单独缩小文件。这取决于您的服务器,您的数据库包含多少个文件。一个简单的数据库有一个数据库文件和一个事务日志文件。
  2. 这样做时我应该考虑什么?:收缩会影响您的索引碎片,请参阅第 3 点。另请注意,您不希望将数据库文件缩小到尽可能小的大小,因为在实际环境中它无论如何都会增长。所以我会调整大小(在你的例子中你给了 7 兆字节),你会在数据库文件中留下 10%-20% 的可用空间,因为它无论如何都会在生产环境中被填充,你可以这样可以节省一些自动生长周期。所以实际数字需要仔细计算。另请注意,您执行的“大空间释放”会使事务日志文件膨胀甚至超过您在 DB 文件中获得的空间。此外,您可能体验到的实际空间增益将小于您在数学上的预期,这意味着在 12GB 数学收缩的情况下,减少了千兆字节!
  3. 之后我应该做些什么吗?:正如我之前提到的,您想要重新索引那些由于 SHRINK 的更改而导致碎片变形的索引。如果您需要对查询统计进行任何特殊处理,我还没有进行足够的实验。
  4. 如果是大数据库呢?我可以以较小的增量缩小它吗?SHRINK 操作可以随时中断,您可以稍后继续。如果可能,我建议在离线数据库上执行它。通过中断和contuniung,它会继续缩小相同的大小。从理论上讲,您可以通过指定不那么紧的目标大小而不是 7 兆字节来以较小的增量缩小,但我想说的是,如果您在生产中执行它,那么就试一试。如您所见,索引碎片和可能的事务日志增长存在问题。所以我只会经历一次。

我们都知道,无论如何都不建议定期进行 SHRINK。我尽量省略你可能知道的所有警告和免责声明。备份,如果可能,不要在家里这样做:)

奖励:在复制环境中,如果您在发布者数据库上执行此操作,则不会导致订阅者数据库缩小(由于它们是 Express 版本,因此可能存在大小问题)。

最后,我的重新索引脚本:

USE YourDBName

DECLARE @TbName VARCHAR(255)
DECLARE @FullTbName VARCHAR(255)
DECLARE @IxName VARCHAR(255)
DECLARE myCursor CURSOR FOR
    SELECT OBJECT_NAME(dmi.object_id) AS TableName,i.name AS IndexName
    FROM sys.dm_db_index_physical_stats(14, NULL, NULL, NULL , 'LIMITED') dmi
    JOIN  sys.indexes i on dmi.object_id = i.object_id and dmi.index_id = i.index_id
    WHERE avg_fragmentation_in_percent > 30
    ORDER BY avg_fragmentation_in_percent
OPEN myCursor
FETCH NEXT FROM myCursor INTO @TbName, @ixName
WHILE @@FETCH_STATUS = 0
BEGIN
    IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES  WHERE TABLE_SCHEMA = 'dba' AND TABLE_NAME = @TbName)
BEGIN
        SET @FullTbName = 'dba.' + @TbName
        IF (@ixName IS NULL)
        BEGIN
            PRINT 'Reindexing Table ' + @FullTbName
            DBCC DBREINDEX(@FullTbName, '', 0)
        END
        ELSE
        BEGIN
             PRINT 'Reindexing Table ' + @FullTbName + ', Index ' + @IxName
             DBCC DBREINDEX(@FullTbName, @IxName, 0)
        END
    END
    FETCH NEXT FROM myCursor INTO @TbName, @ixName
END
CLOSE myCursor
DEALLOCATE myCursor
Run Code Online (Sandbox Code Playgroud)

其中唯一的变量是 14,它可以通过发出 select 获得DB_ID('YourDBName'),并且脚本假定您只对 dba.* 模式中的表感兴趣。