我有一个数据库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分钟后对数据库进行备份,那么备份文件大小为1 Gb,这样我可以看到已经成功清理了未使用的空间。换句话说,上面的Sql代码正常工作( XX分钟后的数据库是)。
问题我需要等到这个查询(缩小操作)完成,所以我尝试执行以下操作:
SELECT percent_complete, start_time, status, command, estimated_completion_time, cpu_time, total_elapsed_time
FROM sys.dm_exec_requests
我在上述查询的结果中找不到有关SHRINKFILE命令的任何信息。
我做错了什么?为什么我看不到DB收缩操作的进度?
我的主要问题是:我怎么能等到SHRINKFILE完成? 例如,我可以从我的C#代码查询发送,在此查询的结果中,我将获得SHRINKFILE操作未完成的信息吗?
答案 0 :(得分:17)
衡量DBCC SHRINKFILE
进度的问题在于,引擎无法确定收缩文件需要完成多少工作。要理解这一点,就要了解DBCC SHRINKFILE
的工作原理。基本上,这个过程是:
那为什么这意味着SQL Server不知道需要做多少工作?因为它不知道文件中的空白空间是多么碎片化。如果事情相当紧凑并且靠近文件的前面,收缩文件将很快进行。如果没有,可能需要很长时间。好消息是,一旦页面在文件中移动,它们就会被移动。取消收缩文件不会撤消/回滚此工作,因此如果缩放文件运行一段时间,然后在它完成之前将其终止,则所有页面移动都保持不变。这意味着您可以在几乎您停止的位置重新启动收缩文件(禁止在文件中创建任何新页面)。
答案 1 :(得分:0)
我以不同的方式解决了这个问题,但是这个解决方案不需要任何轮询或等待线程,这是非常实践的。
此方法不会重新组织表索引,只会从硬盘中删除流文件,并将可用空间回收到操作系统。
重要知道以下代码将在同一个线程上工作;因此,这不会影响收缩过程进度,而只是在应用程序线程上运行它。
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");
}