2010-08-10 50 views
5

Tengo una base de datos SQL Server 2005, e intenté poner índices en los campos apropiados para acelerar el DELETE de registros de una tabla con millones de filas (big_table tiene solo 3 columnas) , pero ahora el tiempo de ejecución DELETE es incluso más largo! (1 hora frente a 13 min, por ejemplo)SQL Server DELETE es más lento con los índices

Tengo una relación entre tablas, y la columna por la que filtro mi DELETE está en la otra tabla. Por ejemplo

DELETE FROM big_table 
WHERE big_table.id_product IN (
SELECT small_table.id_product FROM small_table 
WHERE small_table.id_category = 1) 

Por cierto, también he intentado:

DELETE FROM big_table 
WHERE EXISTS 
(SELECT 1 FROM small_table 
WHERE small_table.id_product = big_table.id_product 
AND small_table.id_category = 1) 

y al mismo tiempo parece correr un poco más rápido que el primero, es todavía mucho más lento con los índices que sin ellos.

creé índices en estos campos:

  1. big_table.id_product
  2. small_table.id_product
  3. small_table.id_category

Mi archivo .ldf crece mucho durante el DELETE.

¿Por qué mis consultas DELETE son más lentas cuando tengo índices en mis tablas? Pensé que se suponía que debían correr más rápido.

ACTUALIZACIÓN

acuerdo, el consenso parece ser índices se ralentizará un enorme DELETE becuase el índice tiene que ser actualizado. Aunque, todavía no entiendo por qué no puede DELETE todas las filas a la vez, y simplemente actualizo el índice una vez al final.

Tenía la impresión de que algunos de mis lecturas indicaban que los índices acelerarían DELETE al hacer búsquedas más rápidas de campos en la cláusula WHERE.

Odetocode.com says:

"índices de trabajo igual de bien en la búsqueda de un registro de comandos borrar y actualizar al igual que para las instrucciones SELECT".

Pero más adelante en el artículo, dice que demasiados índices pueden perjudicar el rendimiento.

Las respuestas a las preguntas bobs:

  1. 55 millones de filas de la tabla
  2. 42 millones de filas que se eliminan
  3. similares SELECT declaración no iría (excepción de tipo 'del sistema.OutOfMemoryException' fue lanzado)

probé las siguientes 2 preguntas:

SELECT * FROM big_table 
WHERE big_table.id_product IN (
SELECT small_table.id_product FROM small_table 
WHERE small_table.id_category = 1) 

SELECT * FROM big_table 
INNER JOIN small_table 
ON small_table.id_product = big_table.id_product 
WHERE small_table.id_category = 1 

Tanto fallidos después de correr durante 25 min con este mensaje de error de SQL Server 2005:

An error occurred while executing batch. Error message is: Exception of type 'System.OutOfMemoryException' was thrown. 

El servidor de la base de datos es una máquina Xeon dual core más antigua con 7,5 GB ram. Es mi base de datos de prueba de juguetes :) por lo que no está ejecutando nada más.

¿Debo hacer algo especial con mis índices después de I CREATE para que funcionen correctamente?

+3

¿Cuántas filas están en la mesa? ¿Cuántas filas se están eliminando? ¿Cuánto tiempo tomaría una declaración SELECT similar para completar? Saber qué tan rápido toma la instrucción SELECT puede dar una idea de cómo los índices afectan a DELETE. – bobs

+0

filas de 55 mil, 42 eliminadas, no completadas, consulte más arriba para obtener más detalles – JohnB

+0

Se necesita más tiempo porque cuando realiza una eliminación, los índices que hacen referencia a su tabla también deben actualizarse. – WOPR

Respuesta

27

Los índices hacen que las búsquedas sean más rápidas, como el índice al final de un libro.

Las operaciones que modifican los datos (como un DELETE) son más lentas, ya que implican manipular los índices. Considere el mismo índice al final del libro. Tiene más trabajo por hacer si agrega, elimina o cambia páginas porque también debe actualizar el índice.

0

También puede probar la extensión de TSQL a BORRAR sintaxis y comprobar si se mejora el rendimiento:

DELETE FROM big_table 
FROM big_table AS b 
INNER JOIN small_table AS s ON (s.id_product = b.id_product) 
WHERE s.id_category =1 
+0

Esto no ayudó para nada; tomó exactamente el mismo tiempo que 'delete from big_table where exists (seleccione 1 de small_table donde small_table.id_product = big_table.id_product y small_table.id_category = 1)' – JohnB

1

Estoy de acuerdo con las sacudidas comentario anterior - Si va a eliminar grandes volúmenes de datos de grandes tablas de eliminación de los índices puede tomar un tiempo además de borrar los datos es el costo de hacer negocios. A medida que borra todos los datos, está causando la reindexación de eventos.

Con respecto al crecimiento del archivo de registro; si no está haciendo nada con sus archivos de registro, puede cambiar al registro Simple; pero le pido que lea sobre el impacto que podría tener en su departamento de TI antes de cambiar.

Si necesita hacer la eliminación en tiempo real; a menudo es un buen trabajo para marcar los datos como inactivos, ya sea directamente en la tabla o en otra tabla y excluir esos datos de las consultas; luego vuelva más tarde y elimine los datos cuando los usuarios no estén mirando un reloj de arena. Hay una segunda razón para cubrir esto; si está eliminando muchos datos de la tabla (que es lo que supongo que se basa en su problema de archivo de registro), entonces probablemente quiera hacer un indexdefrag para reorganizar el índice; ¡Hacer eso fuera de horas es el camino a seguir si no te gustan los usuarios en el teléfono!

0

JohnB borra aproximadamente el 75% de los datos. Creo que lo siguiente habría sido una posible solución y probablemente una de las más rápidas. En lugar de eliminar los datos, cree una nueva tabla e inserte los datos que debe conservar. Cree los índices en esa nueva tabla después de insertar los datos. Ahora suelte la tabla anterior y cambie el nombre del nuevo al mismo nombre que el anterior.

Lo anterior, por supuesto, asume que hay suficiente espacio en disco disponible para almacenar temporalmente los datos duplicados.

0

intentar algo como esto para evitar borrar mayor (y por lo tanto evitar el crecimiento archivo de registro)

declare @continue bit = 1 

-- delete all ids not between starting and ending ids 
while @continue = 1 
begin 

    set @continue = 0 

    delete top (10000) u 
    from <tablename> u WITH (READPAST) 
    where <condition> 

    if @@ROWCOUNT > 0 
     set @continue = 1 

end 
Cuestiones relacionadas