Использование задания агента SQL для вызова процедур в цикле

StackOverflow https://stackoverflow.com/questions/1601077

Вопрос

Я собираю задание на SQL Enterprise Manager 2000 для копирования и удаления записей в паре таблиц базы данных.Мы запустили обычную хранимую процедуру массового копирования и удаления, но она может работать с миллионами строк и, следовательно, зависать на сервере.Мне было интересно попытаться запустить службу единовременно порциями по 100 записей, чтобы сервер не останавливался (это живая веб-база данных).Я хочу, чтобы эта служба запускалась один раз в ночь, именно поэтому я включил ее в задание агента.Есть ли какой-нибудь способ зациклить вызовы хранимых процедур, которые фактически выполняют копирование и удаление, а затем "спят" между каждым вызовом, чтобы дать серверу время наверстать упущенное?Я знаю, что есть команда WAITFOR, но я не уверен, задержит ли это процессор или позволит ему выполнять другие запросы в то же время.

Спасибо!

Это было полезно?

Решение

"Разбиениена части" ваших удалений - предпочтительный способ удаления чрезмерных объемов данных без раздувания файлов журнала транзакций.Сообщение Брэдка является разумным примером этого.

Управление такими циклами лучше всего выполнять в рамках одной хранимой процедуры.Чтобы распределить такую работу во времени, я бы все равно включил ее в процедуру.Вставка WAITFOR в цикл приведет к "паузе" между каждым набором удалений, если вы сочтете это необходимым для решения возможных проблем с параллелизмом.Используйте задание агента SQL, чтобы определить, когда начнется процедура - и если вам нужно убедиться, что она остановится к определенному времени, включите это также в цикл.

Мой подход к этому коду был бы следующим:

--  NOTE: This is a code sample, I have not tested it
CREATE PROCEDURE ArchiveData

    @StopBy DateTime
    --  Pass in a cutoff time.  If it runs this long, the procedure will stop.
AS

DECLARE @LastBatch  int

SET @LastBatch = 1
--  Initialized to make sure the loop runs at least once


WHILE @LastBatch > 0
 BEGIN

    WAITFOR DELAY '00:00:02'
    --  Set this to your desired delay factor

    DELETE top 1000  --  Or however many per pass are desired
     from SourceTable
    --  Be sure to add a where clause if you don't want to delete everything!

    SET @LastBatch = @@rowcount

    IF getdate() > @StopBy
        SET @LastBatch = 0

 END

RETURN 0

Хм.Перечитывание вашего сообщения подразумевает, что вы хотите сначала куда-нибудь скопировать данные, прежде чем удалять их.Чтобы сделать это, я бы настроил временную таблицу и внутри цикла сначала обрезал временную таблицу, затем скопировал первичные ключи ВЕРХНИХ N элементов, вставил в таблицу "архив" через соединение с временной таблицей, затем удалил исходную таблицу также через соединение с временной таблицей.(Просто немного сложнее, чем прямое удаление, не так ли?)

Другие советы

Не беспокойтесь о ожидании между циклами, SQL server должен обрабатывать конфликт между вашим заданием на обслуживание и обычной активностью на сервере.

Что действительно вызывает проблему в подобных ситуациях, так это то, что весь процесс удаления происходит одновременно, внутри одной транзакции.Это приводит к разрыву журнала базы данных и может вызвать проблемы, с которыми, как кажется, вы столкнулись.

Используйте цикл, подобный этому, для удаления управляемыми фрагментами:

DECLARE @i INT
SET @i = 1

SET ROWCOUNT 10000

WHILE @i > 0
BEGIN
    BEGIN TRAN
        DELETE TOP 1000 FROM dbo.SuperBigTable
        WHERE RowDate < '2009-01-01'
    COMMIT

    SELECT @i = @@ROWCOUNT
END
SET ROWCOUNT 0

Вы можете использовать аналогичную логику для своей копии.

WAITFOR позволит другим процессам "пуститься в ход".Я использовал этот метод, чтобы остановить блокировку компьютера при большом УДАЛЕНИИ.Создайте цикл WHILE, удалите блок строк, а затем ПОДОЖДИТЕ несколько секунд (или меньше, в зависимости от того, что подходит).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top