Подтвердить что ты не робот

Прогресс для DBCC SHRINKFILE

У меня есть база данных 21 Gb; 20 Gb из них - файлы (FileStream), и я удаляю все файлы из таблицы, но когда я делаю резервную копию резервного файла по-прежнему 21 ГБ.

Чтобы решить эту проблему, я стал идеей "освободить неиспользуемое пространство".

Итак, я пытаюсь уменьшить мою базу данных следующим образом:

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 Гб, я вижу, что неиспользуемое пространство было успешно очищено. Другими словами, приведенный выше код Sql работает исправно (база данных через XX минут устарела).


Проблема Мне нужно подождать, пока этот запрос (операция сокращения) завершится, поэтому я пытаюсь сделать следующее:

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


Я сделал что-то не так? почему я не вижу прогресса в сокращении работы БД?

И мой главный вопрос: как я могу дождаться завершения SHRINKFILE? Например, могу ли я отправить запрос с кодом С#, и в результате этого запроса я получу информацию о том, что операция SHRINKFILE финиширована или нет?

4b9b3361

Ответ 1

Проблема с измерением прогресса DBCC SHRINKFILE заключается в том, что не существует единого способа для двигателя знать, сколько работы нужно сделать для сжатия файла. Чтобы понять это, нужно знать, как работает DBCC SHRINKFILE. В основном, процесс:

  • Вы объявляете, что хотите сжать файл до определенной точки (скажем, 5 ГБ, с 10 ГБ).
  • Двигатель начнет перемещать страницы с конца файла на следующее открытое пятно рядом с началом файла.

Shrink File Movement

  • Двигатель продолжает работать до тех пор, пока A) он не переместит достаточное количество страниц под вашим заявленным пунктом, чтобы уменьшить размер файла или B), что все пустое пространство находится на задней части файла.

Итак, почему это означает, что SQL Server не знает, сколько работы нужно выполнить? Поскольку он не знает, как фрагментировано ваше пустое пространство в файле. Если все довольно хорошо уплотнено и рядом с файлом, файл сжимается быстро. Если нет, это может занять много времени. Хорошей новостью является то, что как только страницы перемещаются внутри файла, они перемещаются. Отмена сжатого файла не отменяет/откатывает эту работу, поэтому, если у вас есть сжатый файл, работающий некоторое время, а затем убейте его до его завершения, все перемещение этой страницы остается нетронутым. Это означает, что вы можете перезапустить файл сжатия почти в тот момент, когда вы остановились (запрет на любое создание новой страницы в файле).

Ответ 2

Я решу проблему по-другому, но это решение не требует никакого опроса или ожидания потоков, и это очень практично.

Этот подход не приведет к реорганизации индексов таблицы, а только удалит потоковые файлы из жесткого диска и освободит свободное пространство для ОС.

Импортировать, чтобы знать, что приведенный ниже код будет работать в одном и том же потоке; Таким образом, это не повлияет на процесс процесса сжатия, но только запускает его в потоке приложения.

    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");
    }