Использование задания агента SQL для вызова процедур в цикле - PullRequest
2 голосов
/ 21 октября 2009

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

Спасибо!

Ответы [ 3 ]

2 голосов
/ 21 октября 2009

«Упорядочивание» удаляемых файлов - это предпочтительный способ удаления избыточных объемов данных без раздувания файлов журнала транзакций. Пост BradC является разумным примером этого.

Управление такими циклами лучше всего выполнять в рамках одной хранимой процедуры. Чтобы распространить такую ​​работу во времени, я бы все равно оставил ее в процедуре. Вставка 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

Хм. Перечитывание вашей публикации подразумевает, что вы хотите сначала скопировать данные куда-нибудь, прежде чем удалять их. Для этого я бы настроил временную таблицу, и внутри цикла сначала обрежу временную таблицу, затем скопирую первичные ключи элементов TOP N, вставлю в «архивную» таблицу через соединение с временной таблицей, затем удалите исходную таблицу также через соединение с временной таблицей. (Просто немного сложнее, чем прямое удаление, не так ли?)

1 голос
/ 21 октября 2009

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

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

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

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

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

0 голосов
/ 21 октября 2009

WAITFOR позволит другим процессам "пойти". Я использовал эту технику, чтобы остановить большие DELETE, блокирующие машину. Создайте цикл WHILE, удалите блок строк, а затем WAITFOR через несколько секунд (или меньше, в зависимости от того, что подходит).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...