ShrinkDatabase de SQL Server puede producir fragmentación y problemas de rendimiento

En SQL Server se puede utilizar el comando de DBCC SHRINKDATABASE para reducir el espacio ocupado por los archivos de datos y de log de una base de datos.

ShrinkDatabase de SQL Server

 

El problema que tiene SHRINKDATABASE es que, al contrario de lo que pueda parecer, si no se utiliza con cuidado, el resultado puede ser un importante incremento en la fragmentación de los índices, y también de las tablas, lo cual deriva en un empeoramiento del rendimiento de nuestra base de datos SQL Server, e incluso un aumento del espacio ocupado cuando se reconstruyan los índices afectados por la fragmentación.

 

Qué hace el comando DBCC ShrinkDatabase 

El comando SHRINK libera el espacio libre que queda en los archivos de la base de datos, haciendo que en lugar de quedar reservado para el crecimiento de los datos, se 'devuelva' al sistema operativo. La reducción de espacio se produce, pero hay que pensar en el crecimiento de la base de datos. Si no se deja espacio libre contiguo al que utiliza cada tabla, los nuevos datos se crearán en diferentes ubicaciones físicas, se aumentará la fragmentación, y se complicarán los índices y las ordenaciones.

Incluir SHRINKDATABASE entre las operaciones diarias de mantenimiento de una BD SQLServer, por ejemplo, puede provocar un importante problema de fragmentación, ya que los datos que se insertaran podrían quedar almacenados en una ubicación física diferente para cada nuevo día después la ejecución del SHRINK. 

 

Cuando y cómo hay que utilizar Shrink en SQL Server

¿Pero entonces, SHRINK DATABASE sirve para algo? Claro que sirve, en determinados casos. Si en una base de datos SQL Server se eliminan o se truncan tablas, que reducen considerablemente el volumen ocupado por los datos, y no hay previsión de volver a ocupar ese espacio, puede interesar utilizarlo para ajustar mejor la relación entre espacio ocupado y espacio reservado, reduciendo así el tamaño de la base de datos, pero siempre es recomendable dejar un porcentaje de espacio libre reservado tanto para las operaciones diarias de la base de datos como para el crecimiento de los datos con la mínima fragmentación. 

En caso de utilizar el Shrink de SQLServer, para asegurar ese espacio reservado y que el crecimiento no cree problemas de fragmentación y rendimiento, es importante revisar los argumentos que admite el comando, ya que si se informa el segundo argumento con un número la reducción de espacio se realizará dejando ese número como porcentaje de espacio no utilizado que no se devolverá al sistema operativo.

Sintaxis del comando

DBCC SHRINKDATABASE  
( database_name | database_id | 0      
          [ , target_percent ]      
          [ , { NOTRUNCATE | TRUNCATEONLY } ]  
)  
[ WITH NO_INFOMSGS ]

Ejemplo de utilización de Shrink 

Por ejemplo, si acabamos de realizar operaciones de limpieza (eliminar esquemas no utilizados, tablas temporales o simplemente innecesarias) en nuestra base de datos que sabemos que han reducido el espacio ocupado por los datos en un 50%, y queremos reducir el espacio ocupado por los ficheros de la base de datos, pero dejando reservado un 15% de espacio libre para las operaciones diarias, y para el crecimiento que preveemos de la base de datos para el año actual, podríamos ejecutar este comando:

DBCC SHRINKDATABASE (Mi_base_de_datos, 15);

De esta manera el espacio ocupado por los ficheros de datos y de registro de la base de datos se reduciría aproximadamente en un 35%. Si no incluyéramos el parámetro del porcentaje, reduciríamos más el espacio, pero al día siguiente las nuevas inserciones de datos ya comenzarían a necesitar ampliaciones de tamaño de los ficheros que obviamente no se encontrarían en el mismo espacio físico que los datos existentes, y aumentarían la fragmentación de los datos.

Recomendación para reducir la fragmentación

Y ya que hablamos de fragmentación, lo que sí es recomendable incluir en las tareas de mantenimiento periódicas es una reconstrucción de los índices con un REBUILD, cosa que reducirá la fragmentación y mejorará el rendimiento de la DB, aunque pueda incrementar un poco más el espacio utilizado:

ALTER INDEX idx_mitabla_ID ON MiTabla REBUILD;

 

Referencias

Finalmente, enlazo como referencia algunas entradas de blog de otros sitios que explican porqué hacer un Shrink Database normalmente no es buena idea, aportan razones para no utilizar un ShrinkDatabase, o que hacen una demostración práctica de lo que pasa con el espacio y la fragmentación al hacer un ShrinkDatabase

 

¿Conoces algún caso más en el que sea o no recomendable hacer un Shrink? ¿Te has encontrado en alguna ocasión un problema de fragmentación o de rendimiento provocado por una desafortunada utilización de ShrinkDatabase?