Domanda

Sto mettendo insieme un lavoro su SQL Enterprise Manager 2000 per copiare ed eliminare i record in un paio di tabelle del database. Abbiamo eseguito una copia di massa diretta ed eliminato la procedura memorizzata, ma potrebbe essere in esecuzione su milioni di righe e quindi si blocca il server. Ero interessato a provare a eseguire il servizio in blocchi di record di 100 ish alla volta, quindi il server non si fermava (questo è un database web live). Voglio che questo servizio venga eseguito una volta a notte, motivo per cui l'ho inserito in un lavoro di agente. Esiste un modo per eseguire il loop delle chiamate alle procedure memorizzate che eseguono effettivamente la copia e l'eliminazione e quindi "sleep" tra una chiamata e l'altra per dare al server il tempo di recuperare il ritardo? So che c'è il comando WAITFOR, ma non sono sicuro che questo possa trattenere il processore o lasciarlo eseguire altre query nel frattempo.

Grazie!

È stato utile?

Soluzione

" Chunkifying " le tue eliminazioni sono il modo preferito per eliminare quantità eccessive di dati senza gonfiare i file di registro delle transazioni. Il post di BradC ne è un ragionevole esempio.

La gestione di tali loop viene eseguita al meglio in un'unica procedura memorizzata. Per diffondere tale lavoro nel tempo, lo terrei ancora nella procedura. L'inserimento di un WAITFOR nel loop comporterà una "pausa" tra ogni serie di eliminazioni, se lo ritieni necessario per affrontare eventuali problemi di concorrenza. Utilizzare un processo di SQL Agent per determinare quando inizia la procedura e, se è necessario assicurarsi che si interrompa entro un determinato momento, inserirla anche nel ciclo.

Il mio giro su questo codice sarebbe:

--  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

Hmm. La rilettura del post implica che si desidera copiare i dati da qualche parte prima di eliminarli. Per fare ciò, ho impostato una tabella temporanea e all'interno del ciclo prima troncare la tabella temporanea, quindi copiare le chiavi primarie degli elementi TOP N, inserirle nell'archivio " tabella tramite un join alla tabella temporanea, quindi eliminare la tabella di origine anche tramite un join alla tabella temporanea. (Solo un po 'più complesso di una cancellazione diretta, non è vero?)

Altri suggerimenti

Non preoccuparti di aspettare tra i loop, il server SQL dovrebbe gestire la contesa tra il tuo lavoro di manutenzione e l'attività normale sul server.

Ciò che realmente causa il problema in questi tipi di situazioni è che l'intero processo di cancellazione avviene tutto in una volta, all'interno di una singola transazione. Questo fa esplodere il registro per il database e può causare il tipo di problemi che sembra si stiano verificando.

Usa un ciclo come questo per eliminare in blocchi gestibili:

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

Puoi usare una logica simile per la tua copia.

WAITFOR consentirà ad altri processi di "provare". Ho usato questa tecnica per impedire a DELETE di grandi dimensioni di bloccare la macchina. Crea un ciclo WHILE, elimina un blocco di righe e quindi ATTENDI qualche secondo (o meno, qualunque cosa sia appropriata).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top