2011-05-05 20 views
7

Estoy escribiendo un procedimiento para eliminar todas las filas de algunas tablas durante n días.Eliminar un gran número de filas de SQL Server - de manera eficiente y sin bloqueo

Una simple consulta muertos es fácil escribir

DELETE FROM [myTable] 
WHERE [Created] < GETDATE()-30 

Uno de los problemas es que no hay índice en el campo de la fecha - que podría añadir uno, pero yo estaba trabajando alrededor de ella haciendo algo como:

SELECT @var = MAX([ID]) FROM myTable WHERE Created < GETDATE()-30; 
DELETE FROM myTable WHERE ID < @var 

¿Parece un método aceptable?

El problema es que la tabla es enorme, y esta consulta borrará probablemente cientos de miles de filas en cada ejecución.

Al ejecutarlo en un servidor de prueba (un poco lento) tarda una hora más o menos, y elimina la tabla de otros procesos que intentan leer/escribir en ella.

No me molesta demasiado tomarse un tiempo para correr (aunque más rápido es mejor) - pero no puedo tenerlo bloqueando la mesa durante una hora mientras está en ejecución, ya que hay lecturas/escrituras constantes pasando (principalmente escribe).

Mi conocimiento de DB es bastante básico, ya que soy un codificador no un dba.

¿Puede alguien darme un método decente para realizar esta tarea, de la manera más eficiente posible?

+0

¿Por qué no simplemente seleccionar los registros que va a eliminar en una tabla temporal, y luego crear un cursor para eliminar un par de registros de la tabla temporal en cada ejecución? Luego tiene muchas pequeñas instrucciones de eliminación que no deberían bloquear su tabla. – Tejs

+0

Suelta la partición anterior. Si no tiene particiones, debe ver que ... – peufeu

Respuesta

6

Lo que está buscando es una ventana deslizante basada en particiones: How to Implement an Automatic Sliding Window in a Partitioned Table on SQL Server 2005. Particione la tabla por día y puede dejar caer un día completo en una sola operación de cambio de partición a la medianoche. El interruptor de partición es básicamente instantáneo.

Si desea una solución con gastos generales ligeramente más bajos (la partición tiene graves consecuencias y fluctuaciones en toda la aplicación, especialmente cuando los índices deben alinearse, que es un requisito para las operaciones de cambio rápido), debe diseñar su esquema de acuerdo con esta operación. Con 99.99% de confianza, puedo decir que la clave agrupada más a la izquierda de su myTabledebe ser el campo Created. Esto permitiría la eliminación eficiente de lotes (delete top (2500) from myTable where Created < ...). Hay muchas razones por las que desea que se agrupe (más de 2500 a la vez), lo más importante es que debe evitar la escalada de bloqueo y debe mantener el tamaño de cualquier transacción individual dentro de los límites razonables.

3

Su método sufrirá la misma dolencia que una eliminación normal: no tiene un índice en [Creado]. Por lo tanto, su método es más complicado.

Sugiero que cree dicho índice y pruebe la eliminación normal en su servidor de prueba.

Otra sugerencia: ejecutar esto fuera del horario comercial normal a través de un planificador.

0

Crear el índice y realizar la eliminación fuera del horario de oficina son probablemente las mejores cosas para hacer. Sin embargo, si no son opciones, puede crear una vista basada en su consulta y eliminar esa vista, por lo tanto, solo necesita hacer referencia a la tabla una vez, en lugar de dos veces, acelerando las operaciones de E/S.

create view v1 as (select * FROM myTable WHERE Created < GETDATE()-30;) 
delete from v1 
+0

Esto tendría cero efecto. Con la excepción de las vistas indizadas, cuando se utiliza una vista, la definición de la vista se expande y la consulta se ejecuta normalmente (de forma muy similar a como lo haría si ampliara manualmente la definición de vista manualmente). – Justin

3

Para mejorar el rendimiento, debe buscar crear un índice en el campo Creado si esto es algo que desea hacer a menudo.

Posteriormente, se podría utilizar procedimientos de varias horas

DELETE FROM myTable 
WHERE Created < GETDATE()-30 

que he visto reducidos a unos cuantos segundos con el índice y estadísticas Además adecuada.

Los índices son fáciles de crear, y podría haber herramientas disponibles para sugerir el índice y proporcionar la sintaxis. Ejemplo: SQL Tuning Advisor en MS SQL 2005 Management Studio.

+0

Si publica código, XML o muestras de datos, ** por favor ** resalte esas líneas en el editor de texto y haga clic en el botón "muestras de código" ('{}') en la barra de herramientas del editor para formatear y sintaxis ¡destaquelo! –

2

Supongo que no puede indexar la columna Creada (dado que ese es el lugar lógico para comenzar de lo contrario). En función de esa suposición, tendrá problemas de rendimiento y bloqueo. Sin embargo, dado que está utilizando SQL 2005, puede aprovechar algunas características nuevas especificadas en este artículo: http://nayyeri.net/reduce-locks-for-delete-and-update-commands-in-sql-server-2005-with-top-clause

Básicamente, cree una consulta que seleccione todos los registros que desea afectar. Escriba los identificadores de fila (que están indexados) en una tabla temporal. Vincule la tabla temporal a la tabla de la que desea eliminar en función del identificador. Luego use la eliminación por lotes especificada aquí para eliminar grupos a la vez.

De esta manera, crea una tabla temporal en función de sus criterios de fecha (no será eficiente debido a que no es índice, pero puede configurar NOLOCK para que no lo bloquee). A continuación, elimine la tabla en lotes para reducir el bloqueo en la eliminación real.

Cuestiones relacionadas