Este post está patrocinado por Jorge Turrado, MVP de Microsoft, y su magnífico blog Fixed Buffer (en español). Jorge ha donado 100€ para el banco de alimentos en mi iniciativa "¿Te he ayudado? Ayúdame a ayudar a otros". ¡Muchas gracias Jorge!

Icono de borrar base de datos de icons8.com CC BY-ND 3.0El otro día tuve que borrar el contenido completo de una tabla muy grande en una base de datos muy vieja. Estamos hablando de una tabla de log con más de 6 millones de registros.

Cuando te toca hacer una cosa así, aparte del miedo a eliminar algo por error, lo primero que te viene a la mente es utilizar una instrucción DELETE de SQL.

O sea, algo tan sencillo como esto:

DELETE FROM MiTablaDeLogs

Y realmente va a funcionar. Su principal problema es que es muy costosa de ejecutar, ya que lo que hace por debajo es eliminar registro a registro, y generando una transacción para cada uno de ellos. Lo que es peor: genera un bloqueo para cada instrucción de eliminación (por cada DELETE).

Con DELETE, si tienes unos pocos cientos o miles de filas, será muy rápido. Pero si tienes millones, el proceso puede ser muy lento, afectar al rendimiento del servidor de bases de datos y generará un enorme log de transacciones.

La única ventaja de usar DELETE es que, si no quieres eliminar todo el contenido de la tabla, te permite decidir exactamente qué borras (usando una cláusula WHERE). Pero si lo que de verdad quieres hacer es cargarte todo, como era mi caso, es una solución muy mala.

Ahora mismo vamos a ver una opción mucho mejor... Pero antes

Si quieres aprender a programar SQL Server en serio, no te puedes perder los cursos de SQL Server de campusMVP

Otra opción mejor para vaciar una tabla de todos sus datos

Casi todos los gestores de datos tienen una instrucción especial para hacer esto: TRUNCATE TABLE.

Lo que hace esta instrucción es exactamente eso: vaciar de datos la tabla que le indiquemos. Por ejemplo:

TRUNCATE TABLE MiTablaDeLogs

Aunque hace lo mismo que la instrucción DELETE que vimos antes, tiene grandes diferencias con ésta.

En primer lugar está la manera de funcionar. Cómo no se puede restringir lo que se borra (se elimina todo siempre), TRUNCATE no escanea la tabla registro por registro, ni los bloquea ni guarda cada borrado en el log de transacciones. TRUNCATE se carga todo lo que hay bloqueando la tabla entera y guardando una única transacción en el log (bueno esto último no es cierto, pero casi como si lo fuera: reduce el uso del logo a la mínima expresión: no sé cuantificar cuánto).

Por cierto, también bloquea el esquema de la tabla, es decir: no podrás modificar la estructura de la tabla mientras se esta ejecutando, aunque no creo que esto tenga mucha importancia porque no lo vas a hacer de todos modos al mismo tiempo que la borras ¿no?

 Otras diferencias importantes que debes tener en cuenta son que TRUNCATE:

  • Es una instrucción DDL (Data Definition Language) no de consulta.
  • Por lo tanto no devuelve el número de registros eliminados, cosa que DELETE sí hace.
  • Deja los campos autonuméricos con el valor inicial (1 normalmente). DELETE no, por lo que el siguiente registro continuaría con la numeración.
  • No ejecuta triggers asociados al borrado de los datos, si los hubiera (DELETE sí).
  • No deja ninguna página de datos por ahí colgando, cosa que con DELETE sí que puede pasar, dejando a lo mejor muchas páginas en blanco ocupando espacio.
  • No trabaja con vistas indexadas, mientras que DELETE sí.
  • No se puede utilizar dentro de una transacción.

Lógicamente, no te puedes cargar los registros de una tabla que tengan una clave externa con otra y que tengan integridad referencial (una restricción de clave externa),pero eso con ninguna instrucción. Primero tendrías que eliminar los registros dependientes: es la belleza de la integridad referencial en bases de datos.

Aquí puedes leer la documentación oficial de la instrucción TRUNCATE.

¡Espero que te resulte útil! Si es así... ya sabes.

Escrito por un humano, no por una IA