Necesito reducir mi base de datos: acabo de liberar mucho espacio

35

Esta pregunta se hace en varias formas aquí, pero la pregunta se reduce a:

Sé que reducir una base de datos es arriesgado. En este caso, eliminé tantos datos y nunca los volveré a usar.

  • ¿Cómo puedo reducir mi base de datos? ¿Qué archivos encojo?
  • ¿Cuáles deberían ser mis consideraciones al hacer esto?
  • ¿Debo hacer algo después?
  • ¿Qué pasa si es una gran base de datos? ¿Puedo reducirlo en incrementos más pequeños?
Mike Walsh
fuente
2
Luché con esto hace algún tiempo: dba.stackexchange.com/questions/47310/ ... Traté de resumir mi experiencia en mi respuesta
Csaba Toth

Respuestas:

30

Algunas advertencias iniciales:

  1. En general, se conoce como el peor de la práctica de alguna vez reducir un archivo de base de datos de producción o de datos (archivos de registro son otro problema ya que esta pregunta habla). Aconsejo a las personas que no reduzcan sus bases de datos en publicaciones de blog como esta donde hablo sobre "dimensionamiento correcto" y buena planificación. No estoy solo allí ( Paul Randal , Brent Ozar , solo para proporcionar un par de enlaces más). Reducir un índice de archivos de datos o fragmentos de bases de datos, es lento y laborioso en sus recursos, puede ser una carga para su sistema y es simplemente algo malo, generalmente
  2. En este caso, todos sabemos que el riesgo existe, estamos preparados para enfrentarlo, pero liberamos mucho espacio que sabemos que nunca más volveremos a necesitar. Entonces, en este tipo específico de casos, la reducción tiene mucho sentido como una de nuestras opciones.

Si ha leído sobre las preocupaciones y los riesgos y aún necesita hacer esta reducción porque liberó una cantidad significativa de espacio, es de esperar que el resto de esta respuesta lo ayude. Pero tenga en cuenta los riesgos.

Hay dos enfoques principales que dos consideramos aquí:

1.) Reducir Sí, realice la reducción real : considere usar en DBCC SHRINKFILElugar de DBCC SHRINKDATABASE, usted tiene más control sobre lo que se reduce y cómo. Esto va a causar una degradación de rendimiento con seguridad - es una gran operación de hacer un montón de IO. Potencialmente, puede escapar con reducciones repetidas a un tamaño objetivo que se vuelve progresivamente más pequeño.

Este es el ejemplo "A)" en el DBCC SHRINKFILEenlace anterior . Un archivo de datos se está reduciendo a un tamaño de destino de 7 MB en este ejemplo. Este formato es una buena forma de reducirse repetidamente según lo permita su ventana de tiempo de inactividad. Haría esto en las pruebas de desarrollo para ver cómo se ve el rendimiento y qué tan bajo / alto puede ir de un incremento y para determinar el tiempo esperado en la producción. Este es un en línea operación en : puede ejecutarla con usuarios en el sistema que acceden a la base de datos que se está reduciendo, pero habrá una degradación del rendimiento, casi garantizada. Por lo tanto, supervise y mire y vea lo que le está haciendo al servidor, elija una ventana de tiempo de inactividad o un período de actividad más ligera, idealmente.

USE YourDatabase;
GO
DBCC SHRINKFILE (DataFile1, 7);
GO

Recuerde siempre: cada vez que se encoja, fragmenta sus índices y debe hacer una reconstrucción del índice si va a encogerse en trozos durante un período prolongado de tiempo. Ahora está incurriendo en ese costo cada vez si no puede hacerlo todo en una sola ventana.

2.) Nueva base de datos : puede crear una nueva base de datos y migrar datos a ella. Tendría que escribir la base de datos vacía y todas sus claves, índices, objetos, procesos, funciones, etc. y luego migrar datos a ella. Puede escribir scripts para esto o puede usar una herramienta como SQL Data Compare de Red Gate u otros proveedores con herramientas similares. Esto es más trabajo de configuración de su lado, más desarrollo y pruebas, y dependiendo de su entorno también puede eliminar su ventana de tiempo de inactividad, pero también es una opción a considerar.

Cuando me veo obligado a reducir una base de datos Si este fuera mi entorno, trataría de dejar una cantidad considerable / considerable de espacio en blanco en el archivo de datos porque me gusta ser un disco duro y me gustaría estar preparado para un crecimiento futuro / inesperado. Por lo tanto, estaría bien devolver el espacio si elimináramos la mayoría del espacio, pero nunca confiaría en los que dicen "pero nunca volverá a crecer" y aún dejaría algo de espacio en blanco. La ruta con la que probablemente iría ( suspiro ) es el enfoque de reducción si tuviera ventanas de tiempo de inactividad más pequeñas y no No quiera incurrir en la complejidad de crear una base de datos vacía y migrar datos a ella. Por lo tanto, lo reduciría un montón de veces de forma incremental (en función de cuántas veces pensé que necesitaba basarme en mis pruebas en dev y el tamaño deseado. Elegir progresivamente un tamaño de archivo más pequeño) y luego reconstruir los índices ... Y luego ' Nunca le dije a nadie que reduje mi base de datos ;-)

Mike Walsh
fuente
1
Agregaría el caso especial de que si eliminaste muchos datos de un montón (especialmente del medio del montón) no podrás recuperar ese espacio hasta que le agregues un índice agrupado (con suerte para siempre), y luego suelte el índice agrupado después (convirtiéndolo de nuevo en un montón). Por supuesto, si el montón se trunca regularmente, entonces no hay preocupaciones. Pero aún vale la pena mencionarlo.
Jonathan Fite
¿Alguien puede explicar la implicación de NOTRUNCATE AND TRUNCATEONLY, aparentemente este último no reorganiza las páginas y, por lo tanto, no causa la fragmentación del índice?
David García
4
  1. ¿Cómo puedo reducir mi base de datos? ¿Qué archivos encojo? : Puede reducir los archivos individualmente mediante el DBCC SHRINKFILEcomando que menciona. Depende de su servidor de cuántos archivos consta su base de datos. Una base de datos simple tiene un archivo de base de datos y un archivo de registro de transacciones.
  2. ¿Cuáles deberían ser mis consideraciones al hacer esto?: el encogimiento afecta la fragmentación de su índice, vea el tercer punto. También tenga en cuenta que no desea reducir el archivo de la base de datos a un tamaño que sea lo mínimo posible, porque en un entorno del mundo real crecerá de todos modos. Por lo tanto, ajustaría el tamaño (en su ejemplo, dio 7 megabytes) de manera que dejaría un 10% -20% de espacio libre en el archivo de la base de datos, porque de todos modos se llenará en el entorno de producción, y puede guarda algunos ciclos de crecimiento automático de esa manera. Entonces, el número real necesita un cálculo cuidadoso. También tenga en cuenta que el "gran espacio libre" que realizó hincharía el archivo de registro de transacciones incluso más que el espacio que ganó dentro del archivo DB. Además, la ganancia de espacio real que puede experimentar será menor de lo que matemáticamente espera. Entonces, digamos que matemáticamente liberaste 12 conciertos,
  3. ¿Debo hacer algo después? : Como mencioné anteriormente, desea reindexar esos índices cuya fragmentación se distorsionó como resultado de los cambios de SHRINK. No he experimentado lo suficiente si necesita hacer algo especial sobre las estadísticas de consulta.
  4. ¿Qué pasa si es una gran base de datos? ¿Puedo reducirlo en incrementos más pequeños? La operación SHRINK puede interrumpirse en cualquier momento y puede continuar más tarde. Aconsejaría realizarlo en una base de datos fuera de línea si es posible. Sin embargo, al interrumpir y continuar, avanzaría el mismo tamaño de contracción. Teóricamente, puede reducirse en incrementos más pequeños especificando un tamaño objetivo menos ajustado en lugar de 7 megabytes, pero diría que si lo está realizando en producción, entonces solo inténtelo. Como puede ver, hay problemas con la fragmentación del índice y el posible crecimiento del registro de transacciones. Así que pasaría por esto solo una vez.

Todos sabemos que de todos modos no se recomienda hacer SHRINK regularmente. Intento omitir todas las advertencias y renuncias que probablemente conozcas de todos modos. Copia de seguridad, y no hagas esto en casa si es posible :)

Bonificación: en el entorno de replicación si realiza esto en la base de datos del editor, no hará que las bases de datos del suscriptor se reduzcan (lo que puede tener el problema de tamaño porque son ediciones Express).

Finalmente, mi script reindex:

USE YourDBName

DECLARE @TbName VARCHAR(255)
DECLARE @FullTbName VARCHAR(255)
DECLARE @IxName VARCHAR(255)
DECLARE myCursor CURSOR FOR
    SELECT OBJECT_NAME(dmi.object_id) AS TableName,i.name AS IndexName
    FROM sys.dm_db_index_physical_stats(14, NULL, NULL, NULL , 'LIMITED') dmi
    JOIN  sys.indexes i on dmi.object_id = i.object_id and dmi.index_id = i.index_id
    WHERE avg_fragmentation_in_percent > 30
    ORDER BY avg_fragmentation_in_percent
OPEN myCursor
FETCH NEXT FROM myCursor INTO @TbName, @ixName
WHILE @@FETCH_STATUS = 0
BEGIN
    IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES  WHERE TABLE_SCHEMA = 'dba' AND TABLE_NAME = @TbName)
BEGIN
        SET @FullTbName = 'dba.' + @TbName
        IF (@ixName IS NULL)
        BEGIN
            PRINT 'Reindexing Table ' + @FullTbName
            DBCC DBREINDEX(@FullTbName, '', 0)
        END
        ELSE
        BEGIN
             PRINT 'Reindexing Table ' + @FullTbName + ', Index ' + @IxName
             DBCC DBREINDEX(@FullTbName, @IxName, 0)
        END
    END
    FETCH NEXT FROM myCursor INTO @TbName, @ixName
END
CLOSE myCursor
DEALLOCATE myCursor

La única variable en esto es el 14, que se puede obtener emitiendo select DB_ID('YourDBName'), y el script asume que solo le interesan las tablas en el esquema dba. *.

Csaba Toth
fuente
2
Para la reconstrucción del índice, tenga en cuenta que DBREINDEX fue desaprobado en SQL 2005. En lugar de la gran secuencia de comandos con cursores, puede usar: EXEC sp_MSForeachtable @ Command1 = "¿ALTERAR EL ÍNDICE TODO? RECONSTRUIR" Espero que esto ayude a alguien.
KISS
2

Has escuchado todas las advertencias sobre la reducción de las bases de datos y todas son ciertas. Fragmentará sus índices y, en general, arruinará su base de datos y no debe hacerse en un sistema de producción.

Pero, generalmente lo hago semanalmente cuando restauro una copia de seguridad en mi estación de trabajo debido al espacio en mi unidad SSD. Eso sí, no escribí este guión, pero lo encontré hace años. En otras bases de datos [250 GB], creé un paquete SSIS que transferirá las tablas que necesito y luego recreará los índices para esa sensación de índice tan fresca.

DECLARE @DBFileName SYSNAME

DECLARE @TargetFreeMB INT

DECLARE @ShrinkIncrementMB INT

SET @DBFileName = 'Set Name of Database file to shrink'

-- Set Desired file free space in MB after shrink

SET @TargetFreeMB = 500
-- Set Increment to shrink file by in MB
SET @ShrinkIncrementMB = 100

SELECT [FileSizeMB] = convert(NUMERIC(10, 2),
round(a.size / 128., 2)),

[UsedSpaceMB] = convert(NUMERIC(10, 2),

round(fileproperty(a.NAME, 'SpaceUsed') / 128., 2)),

[UnusedSpaceMB] = convert(NUMERIC(10, 2),

round((a.size - fileproperty(a.NAME, 'SpaceUsed')) / 128., 2)),

[DBFileName] = a.NAME

FROM sysfiles a

DECLARE @sql VARCHAR(8000)
DECLARE @SizeMB INT
DECLARE @UsedMB INT

SELECT @SizeMB = size / 128.
FROM sysfiles
WHERE NAME = @DBFileName

SELECT @UsedMB = fileproperty(@DBFileName, 'SpaceUsed') / 128.

SELECT [StartFileSize] = @SizeMB
    ,[StartUsedSpace] = @UsedMB
    ,[DBFileName] = @DBFileName

WHILE @SizeMB > @UsedMB + @TargetFreeMB + @ShrinkIncrementMB

BEGIN
    SET @sql = 'dbcc shrinkfile ( ' + @DBFileName + ', ' + convert(VARCHAR(20), @SizeMB - @ShrinkIncrementMB) + ' ) '

    PRINT 'Start ' + @sql
    PRINT 'at ' + convert(VARCHAR(30), getdate(), 121)

    EXEC (@sql)

    PRINT 'Done ' + @sql
    PRINT 'at ' + convert(VARCHAR(30), getdate(), 121)

    SELECT @SizeMB = size / 128.
    FROM sysfiles
    WHERE NAME = @DBFileName

    SELECT @UsedMB = fileproperty(@DBFileName, 'SpaceUsed') / 128.

    SELECT [FileSize] = @SizeMB
        ,[UsedSpace] = @UsedMB
        ,[DBFileName] = @DBFileName
END

SELECT [EndFileSize] = @SizeMB
    ,[EndUsedSpace] = @UsedMB
    ,[DBFileName] = @DBFileName

SELECT [FileSizeMB] = convert(NUMERIC(10, 2), round(a.size / 128., 2))

    ,[UsedSpaceMB] = convert(NUMERIC(10, 2), round(fileproperty a.NAME, 'SpaceUsed') / 128., 2))

,[UnusedSpaceMB] = convert(NUMERIC(10, 2), round((a.size - fileproperty(a.NAME, 'SpaceUsed')) / 128., 2))

,[DBFileName] = a.NAME

FROM sysfiles a
usuario1207758
fuente
1

Esta cita a continuación es directamente de Microsoft (se aplica a las versiones 2008-2016) y brinda orientación sobre si / cuándo y cómo debe usar el DBCC SHRINKFILEcomando.

https://msdn.microsoft.com/en-us/library/ms189493.aspx

Mejores prácticas

Tenga en cuenta la siguiente información cuando planee reducir un archivo:

  • Una operación de reducción es más eficaz después de una operación que crea mucho espacio no utilizado, como una tabla truncada o una operación de caída de tabla.
  • La mayoría de las bases de datos requieren algo de espacio libre para estar disponibles para las operaciones diarias normales. Si reduce una base de datos repetidamente y observa que el tamaño de la base de datos vuelve a crecer, esto indica que el espacio que se redujo es necesario para las operaciones regulares. En estos casos, reducir la base de datos repetidamente es una operación desperdiciada.
  • Una operación de reducción no conserva el estado de fragmentación de los índices en la base de datos y, en general, aumenta la fragmentación hasta cierto punto. Esta es otra razón para no reducir repetidamente la base de datos.
  • Reduzca varios archivos en la misma base de datos secuencialmente en lugar de concurrentemente. La contención en las tablas del sistema puede causar demoras debido al bloqueo.
g2server
fuente