Pregunta

Estoy preparando un trabajo en SQL Enterprise Manager 2000 para copiar y eliminar registros en un par de tablas de bases de datos. Hemos ejecutado un procedimiento almacenado directo de copia masiva y eliminación, pero podría estar ejecutándolo en millones de filas y, por lo tanto, bloquea el servidor. Estaba interesado en intentar ejecutar el servicio en fragmentos de registro de 100 ish a la vez, para que el servidor no se detenga (esta es una base de datos web en vivo). Quiero que este servicio se ejecute una vez por noche, por eso lo puse en un trabajo de agente. ¿Hay alguna manera de repetir las llamadas a los procedimientos almacenados que realmente copian y eliminan, y luego "dormir"? entre cada llamada para darle tiempo al servidor para ponerse al día? Sé que existe el comando WAITFOR, pero no estoy seguro de si esto mantendrá el procesador o permitirá que ejecute otras consultas mientras tanto.

¡Gracias!

¿Fue útil?

Solución

" Troceado " sus eliminaciones es la forma preferida de eliminar cantidades excesivas de datos sin acumular archivos de registro de transacciones. La publicación de BradC es un ejemplo razonable de esto.

La gestión de dichos bucles se realiza mejor dentro de un único procedimiento almacenado. Para difundir tal trabajo con el tiempo, aún lo mantendría en el procedimiento. Insertar un WAITFOR en el bucle pondrá una " pausa " entre cada conjunto de eliminaciones, si lo considera necesario para tratar posibles problemas de concurrencia. Use un trabajo de Agente SQL para determinar cuándo comienza el procedimiento, y si necesita asegurarse de que se detenga en un momento determinado, también incorpore el ciclo.

Mi giro en este código sería:

--  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. Volver a leer su publicación implica que primero desea copiar los datos en algún lugar antes de eliminarlos. Para hacer eso, configuraría una tabla temporal, y dentro del bucle primero truncaría la tabla temporal, luego copiaría las claves primarias de los elementos TOP N, insertar en el " archivo " tabla a través de una unión a la tabla temporal, luego elimine la tabla fuente también a través de una unión a la tabla temporal. (Solo un poco más complejo que una eliminación directa, ¿no?)

Otros consejos

No se preocupe por esperar entre bucles, el servidor SQL debe manejar la disputa entre su trabajo de mantenimiento y la actividad regular en el servidor.

Lo que realmente causa el problema en este tipo de situaciones es que todo el proceso de eliminación ocurre de una vez, dentro de una sola transacción. Esto explota el registro de la base de datos y puede causar el tipo de problemas que parece que está experimentando.

Use un bucle como este para eliminar en fragmentos manejables:

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

Puede usar una lógica similar para su copia.

WAITFOR permitirá que otros procesos 'tengan una oportunidad'. He usado esta técnica para evitar que DELETE grande bloquee la máquina. Cree un ciclo WHILE, elimine un bloque de filas y luego espere unos segundos (o menos, lo que sea apropiado).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top