¿La "tabla vacía" de SQL Server es lenta después de eliminar todos los registros (12 millones)?

27

Tengo una instancia de SQL Server 2008 con aproximadamente 150 columnas. Anteriormente llené esta tabla con aproximadamente 12 millones de entradas, pero desde entonces la borré en preparación para un nuevo conjunto de datos.

Sin embargo, los comandos que una vez corrió al instante en una mesa vacía, como count(*)y select top 1000en SQL Management StudioAHorA eones para funcionar.

SELECT COUNT(*) FROM TABLE_NAME 

tardó más de 11 minutos en devolver 0 y SELECT TOP 1000tardó casi 10 minutos en devolver una tabla vacía.

También he notado que el espacio libre en mi disco duro ha desaparecido literalmente (de alrededor de 100G a 20G). Lo único que sucedió fue una sola consulta que ejecuté:

DELETE FROM TABLE_NAME

¿¡¿Qué sucede?!?


fuente
55
¿Qué modelo de recuperación usa su base de datos? Si está "Completo", su instancia de SQL almacenará un registro de todas esas eliminaciones, que podrían ser a dónde fue su espacio libre. Si la recuperación completa es un requisito, recomiendo usar en TRUNCATE TABLElugar de DELETE FROM.
Tullo_x86
2
150 columnas? Esa tabla puede estar demasiado llena: la mayoría de las tuplas deberían ser mucho más pequeñas. Sin embargo, es imposible decirlo sin contexto completo.
Clockwork-Muse

Respuestas:

42

Ya te han dicho por qué TRUNCATEsería mucho más rápido / mejor / más sexy que DELETE, pero aún queda una pregunta por responder:

¿Por qué es SELECTmás lento después de DELETE completar ?

Eso es porque DELETEsolo ha fantasmado las filas. La tabla es tan grande como cuando tenía 12 millones de filas, aunque no tiene ninguna. Para contar las filas (0), se necesita tanto tiempo como para contar 12 millones de filas. Con el tiempo, el proceso de limpieza de fantasmas recolectará basura estos registros fantasmas y desasignará páginas que contengan solo fantasmas, y sus SELECT se acelerarán. Pero en este momento, si se registra, Skipped Ghosted Records/secperfmon probablemente se dispare durante SELECT COUNT(*). También podría acelerar las cosas mediante la reconstrucción de la tabla: ALTER TABLE ... REBUILD.

TRUNCATE También se habría ocupado de este problema, ya que no deja fantasmas atrás.

Consulte también Dentro del motor de almacenamiento: limpieza fantasma en profundidad .

Remus Rusanu
fuente
13

DELETElas instrucciones eliminan filas de una tabla de una en una, registrando cada fila en la tabla transaction logy manteniendo la log sequence number (LSN)información. Como mencionó que su tabla tenía datos enormes (12 millones de registros), después de eliminar el disco duro, compruebe el tamaño del archivo de registro de la base de datos. Probablemente habría crecido.

una mejor manera hubiera sido:

TRUNCATE TABLE_NAME

fuente
2
+1, exactamente lo mismo para Oracle DB. Si usa declaraciones que provocan el registro de registros, ralentizará la base de datos con el tiempo.
Petro Semeniuk
@PetroSemeniuk De lo que recuerdo en Oracle, eliminar deja solo la marca de aguas altas, truncar restablecerá la marca de aguas altas. Creo que cualquier operación que requiera un escaneo completo escaneará los bloques hasta la marca de nivel máximo. Por lo tanto, la eliminación podría ayudar a las operaciones indexadas, pero no a los escaneos. TRUNCATE fue la operación adecuada.
Glenn
3

(Este fue originalmente un comentario a la respuesta de @ DaveE, pero lo puse en su propia respuesta porque se alargó)

TRUNCATE Es una operación registrada. Tiene que ser de otra manera no es compatible con ACID. Sin embargo, las diferencias entre TRUNCATEy DELETE:

  • Uso de espacio de registro: TRUNCATEsolo registra páginas / extensiones * liberadas, mientras que DELETEregistra filas individuales.
  • Uso de bloqueo: TRUNCATEgeneralmente usará menos bloqueos, ya que requiere un bloqueo de tabla y bloqueos de página, en lugar de DELETEusar bloqueos de fila **.
  • IDENTITYsecuencias: TRUNCATErestablece la secuencia de identidad en una tabla, si está presente.

(* Una extensión = 8 páginas. TRUNCATERegistrará / eliminará extensiones si son todas de esa tabla, de lo contrario registrará / eliminará páginas de extensiones mixtas.

** Un efecto secundario de esto es que DELETE FROM TABLEpotencialmente puede dejar páginas vacías asignadas a la tabla, dependiendo de si la operación puede obtener un bloqueo exclusivo de la tabla o no).

Entonces (volviendo a la pregunta original), TRUNCATE TABLEes definitivamente mejor que DELETE FROM TABLEsi está vaciando la tabla pero quiere mantener la estructura (NB: TRUNCATEno se puede usar en una tabla a la que hace referencia una clave externa de otra tabla).

Como se señaló en el comentario de @ Tullo, también verifique el modelo de recuperación de su base de datos: si está lleno, entonces debe comenzar a tomar copias de seguridad de registros o cambiar su modelo de recuperación a simple. Una vez que haya hecho cualquiera de estos, probablemente desee reducir su archivo de registro como una operación única (NB: solo archivo de registro ) para reclamar todo ese espacio libre.

Finalmente, otra cosa a tener en cuenta: estadísticas de tabla. ejecute UPDATE STATISTICS <TABLENAME>' afterTRUNCATE /DELETE` para que el optimizador de consultas no se vea afectado por estadísticas antiguas.

Simon Righarts
fuente
2

(NOTA: no soy un DBA) DELETE es una operación registrada, y no libera el espacio utilizado. Probablemente tenga un registro de transacciones grande que ocupa espacio y escaneos de tablas ejecutándose en el espacio de tablas 'vacío'. Supongo que necesita borrar el registro de transacciones y reducir su base de datos. Este artículo de StackOverflow debería ayudarlo a comenzar.

Y use TRUNCATE TABLE cuando quiera hacer esto en el futuro.

EDITAR: Mi declaración sobre TRUNCATE no se registró fue un error. remoto.

DaveE
fuente