Los métodos de aceleración de un enorme DELETE FROM , sin cláusulas

dba.stackexchange https://dba.stackexchange.com/questions/1750

  •  16-10-2019
  •  | 
  •  

Pregunta

El uso de SQL Server 2005.

Estoy realizando un enorme Eliminar en donde sin cláusulas. Es básicamente equivalente a una instrucción TRUNCATE TABLE - excepto que no estoy autorizado a utilizar TRUNCATE. El problema es que la mesa es enorme - 10 millones de filas, y se tarda más de una hora en completarse. ¿Hay alguna manera de hacer que sea más rápido y sin:

  • Uso Truncar
  • Deshabilitar o eliminar índices?

La camiseta de registro ya está en un disco independiente.

Cualquier sugerencia bienvenida!

¿Fue útil?

Solución

Lo que puede hacer es eliminaciones por lotes como este:

SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
    DELETE TOP (xxx) MyTable

donde XXX es, por ejemplo, 50000

Una modificación de este, si desea eliminar un porcentaje muy alto de las filas ...

SELECT col1, col2, ... INTO #Holdingtable
           FROM MyTable WHERE ..some condition..

SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
    DELETE TOP (xxx) MyTable WHERE ...

INSERT MyTable (col1, col2, ...)
           SELECT col1, col2, ... FROM #Holdingtable

Otros consejos

Se puede usar la cláusula TOP para hacer esto fácilmente:

WHILE (1=1)
BEGIN
    DELETE TOP(1000) FROM table
    IF @@ROWCOUNT < 1 BREAK
END

Estoy de acuerdo con las sugerencias a sus lotes eliminaciones en trozos manejables si no son capaces de utilizar TRUNCATE, y yo como la gota / crear sugerencia para que de originalidad, pero tengo curiosidad sobre el siguiente comentario en su pregunta:

Es básicamente equivalente a una instrucción TRUNCATE TABLE - excepto que no estoy autorizado a utilizar TRUNCATE

supongo la razón de esta restricción tiene que ver con la seguridad que debe concederse para truncar directamente una mesa y el hecho de que se le permitiría truncar tablas distintas de la que usted se refiere a.

Si se asume que es el caso, me pregunto si es conveniente tener un procedimiento almacenado que crea tabla usa TRUNCATE y usos "se ejecutan como" sería considerado una alternativa viable a la concesión de derechos de seguridad necesarias para truncar la tabla directamente.

Con suerte, esto le dará la velocidad que necesita y al mismo tiempo hacer frente a los problemas de seguridad que su empresa puede tener con la adición de su cuenta a la función db_ddladmin.

Otra ventaja de utilizar un procedimiento almacenado de esta manera es que el procedimiento almacenado en sí podría ser bloqueado hacia abajo de modo que sólo cuenta específica (s) se permite a utilizarlo.

Si por alguna razón esto no es una solución aceptable y su necesidad de disponer de los datos de esta tabla eliminado es algo que hay que hacer una vez al día / hora / etc, yo solicito que un trabajo del Agente SQL fue creado para truncar la tabla a una hora programada cada día.

Espero que esto ayude!

A excepción truncado .. eliminar sólo en lotes puede ayudar.

Se podría eliminar la tabla y volver a crearlo, con todas las limitaciones y los índices, por supuesto. En Management Studio usted tiene la opción de escritura de una mesa para caer y crear, por lo que debe ser una opción trivial. Pero esto sólo si se le permite hacer acciones DDL, que veo que no es realmente una opción.

Dado que esta cuestión es una referencia tan importante les dejo el código que realmente me ayudó a entender borrar con bucles y mensajería dentro de un bucle para seguir el progreso.

La consulta se modifica a partir esta pregunta duplicado . Crédito para @RLF para la base de consulta.

CREATE TABLE #DelTest (ID INT IDENTITY, name NVARCHAR(128)); -- Build the test table
INSERT INTO #DelTest (name) SELECT name FROM sys.objects;  -- fill from system DB
SELECT COUNT(*) TableNamesContainingSys FROM #deltest WHERE name LIKE '%sys%'; -- check rowcount
go
DECLARE @HowMany INT;
DECLARE @RowsTouched INT;
DECLARE @TotalRowCount INT;
DECLARE @msg VARCHAR(100);
DECLARE @starttime DATETIME 
DECLARE @currenttime DATETIME 

SET @RowsTouched = 1; -- Needs to be >0 for loop to start
SET @TotalRowCount=0  -- Total rows deleted so far is 0
SET @HowMany = 5;     -- Variable to choose how many rows to delete per loop
SET @starttime=GETDATE()

WHILE @RowsTouched > 0
BEGIN
   DELETE TOP (@HowMany)
   FROM #DelTest 
   WHERE name LIKE '%sys%';

   SET @RowsTouched = @@ROWCOUNT; -- Rows deleted this loop
   SET @TotalRowCount = @TotalRowCount+@RowsTouched; -- Increment Total rows deleted count
   SET @currenttime = GETDATE();
   SELECT @msg='Deleted ' + CONVERT(VARCHAR(9),@TotalRowCount) + ' Records. Runtime so far is '+CONVERT(VARCHAR(30),DATEDIFF(MILLISECOND,@starttime,@currenttime))+' milliseconds.'
   RAISERROR(@msg, 0, 1) WITH NOWAIT;  -- Print message after every loop. Can't use the PRINT function as SQL buffers output in loops.  

END; 
SELECT COUNT(*) TableNamesContainingSys FROM #DelTest WHERE name LIKE '%sys%'; -- Check row count after loop finish
DROP TABLE #DelTest;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a dba.stackexchange
scroll top