DBCC SHRINKFILE 的进展

问题描述 投票:0回答:2

我有一个 数据库 21 GB;其中 20 GB 是文件 (FileStream),我已从表中删除所有文件,但当我进行备份时,备份文件仍然是 21 GB

为了解决这个问题,我提出了“释放未使用的空间”的想法。

所以我正在尝试缩小我的数据库,如下所示:

USE Db;
GO
-- Truncate the log by changing the database recovery model to SIMPLE.
ALTER DATABASE Db
SET RECOVERY SIMPLE;
GO
-- Shrink the truncated log file to 1 MB.
DBCC SHRINKFILE (Db, 100);
GO
-- Reset the database recovery model.
ALTER DATABASE Db
SET RECOVERY FULL;
GO

SELECT file_id, name
FROM sys.database_files;
GO
DBCC SHRINKFILE (1, TRUNCATEONLY);

如果我在XX分钟后对数据库进行备份,那么备份文件大小为1GB,这样我可以看到未使用的空间已成功清理。换句话说,上面的Sql代码工作正常(XX分钟后的数据库是schrunk)。


问题我需要等到这个查询(收缩操作)完成,所以我尝试执行以下操作:

SELECT percent_complete, start_time, status, command, estimated_completion_time, cpu_time, total_elapsed_time
FROM sys.dm_exec_requests

我在上述查询的结果中找不到有关 SHRINKFILE 命令的任何信息。

enter image description here


我做错了什么吗?为什么我看不到DB收缩操作的进度?

我的主要问题是:我怎样才能等到SHRINKFILE完成? 例如,我可以从 C# 代码查询发送,并在此查询的结果中我将获得 SHRINKFILE 操作是否完成的信息吗?

c# sql-server sql-server-2012
2个回答
18
投票

测量

DBCC SHRINKFILE
进度的问题在于,引擎没有一致的方法来了解缩小文件需要完成多少工作。要理解这一点,就要了解
DBCC SHRINKFILE
是如何工作的。基本上,过程是:

  • 您声明要将文件缩小到某个点(例如 5 GB, 从 10 GB 下降)。
  • 引擎将开始将页面从文件末尾移动到文件开头附近的下一个打开位置。

Shrink File Movement

  • 引擎继续运行,直到 A) 在您声明的点下移动了足够的页面,从而可以减小文件大小,或者 B) 所有空白空间都位于文件的后端。

那么为什么这意味着 SQL Server 不知道需要完成多少工作呢?因为它不知道文件中的空白空间有多碎片。如果内容压缩得相当好并且靠近文件的前面,则收缩文件会很快完成。如果没有,可能需要很长时间。好消息是,一旦页面在文件中移动,它们就会被移动。取消收缩文件不会撤消/回滚此工作,因此,如果收缩文件运行了一段时间,然后在其完成之前将其终止,则所有页面移动都保持不变。这意味着您可以在几乎您离开的位置重新启动收缩文件(禁止在文件内创建任何新页面)。


1
投票

我用不同的方式解决了这个问题,但是这个解决方案不需要任何轮询或等待线程,非常实用。

此方法不会重新组织表索引,而只会从硬盘中删除流文件并回收操作系统的可用空间。

重要的是要知道以下代码将在同一线程上运行;因此,这不会通知您收缩进程的进度,而只会在应用程序线程上运行它。

    var db = EFDbContext;
    try 
    {
        db.ExecuteSqlCommand(@"USE [master]

                                   ALTER DATABASE DatabaseName
                                   SET RECOVERY SIMPLE");

        db.ExecuteSqlCommand(@"USE [master]

                                   EXEC sp_filestream_force_garbage_collection 'DatabaseName'");

        db.ExecuteSqlCommand(@"USE [master]

                                   EXEC sp_filestream_force_garbage_collection 'DatabaseName'");
      }

    }
    catch (Exception e)
    {
      throw new DatabaseException(e.Message, e);
    }
    finally
    {
             db.ExecuteSqlCommand(@"USE [master]
                                    ALTER DATABASE DatabaseName
                                    SET RECOVERY FULL");
    }
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.