Liberar tabla de SQL Server de espacio no utilizado

11

Tengo una tabla en SQL Server 2012 Express con mucho espacio no utilizado.

Necesito liberar espacio en la base de datos.

El | NOMBRE | FILAS | RESERVADO | DATOS | INDICE_SIZE | SIN USAR |
| ------------- | -------- | -------------- | ----------- --- | ------------ | -------------- |
El | MyTableName | 158890 | 8928296 KB | 5760944 KB | 2248 KB | 3165104 KB |

¿Cómo consigo que SQL libere el 3165104KB?

Ya he intentado:

Alter table MyTableName Rebuild
DBCC CLEANTABLE (MyDbName,"MyTableName ", 0)
ALTER INDEX ALL ON MyTableName REORGANIZE ; 
ALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF) 

Aquí está la tabla:

CREATE TABLE [dbo].[MyTableName](
    [ImageID] [int] IDENTITY(1,1) NOT NULL,
    [DateScan] [datetime] NULL,
    [ScanImage] [image] NULL,
 CONSTRAINT [PK_Image] PRIMARY KEY CLUSTERED 
(
    [ImageID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
    ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

Lo único que hemos hecho es reemplazar ScanImageen cada fila con una imagen mucho más pequeña (así es la cantidad de espacio no utilizado).

DermFrench
fuente

Respuestas:

10

Lo único que hemos hecho es reemplazar ScanImagecada fila con una imagen mucho más pequeña (así es la cantidad de espacio no utilizado)

Después de experimentar un poco, el método más eficaz en el espacio sería soltar la unidad de asignación y repoblarla (si tiene una ventana de mantenimiento para hacerlo).

El código de ejemplo que logró la mejor reducción de espacio para mí con la estructura de la tabla en la pregunta es:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

SET XACT_ABORT ON;

BEGIN TRAN

SELECT [ImageID],
       [ScanImage]
INTO   #Temp
FROM   [dbo].[MyTableName]

ALTER TABLE [dbo].[MyTableName]
  DROP COLUMN [ScanImage]

/*Allocation unit not removed until after this*/
ALTER INDEX PK_Image ON MyTableName REBUILD

ALTER TABLE [dbo].[MyTableName]
  ADD [ScanImage] IMAGE NULL

UPDATE [dbo].[MyTableName]
SET    [ScanImage] = T.[ScanImage]
FROM   [dbo].[MyTableName] M
       JOIN #Temp T
         ON M.ImageID = T.[ImageID]

DROP TABLE #Temp

COMMIT 

Todo está en una transacción, por lo que si la máquina falla, se revertirá. Probablemente podría funcionar con algún manejo de errores o al menos SET XACT_ABORT ON. Solía SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;evitar que ocurrieran modificaciones concurrentes durante o después de la copia y que se perdieran.

El número de páginas LOB reservadas después de reducir el tamaño de un imageen todas las filas fue el siguiente:

+ ------------------------------------------------- - + --------------------- + ------------------------- +
El | Evento | lob_used_page_count | lob_reserved_page_count |
+ ------------------------------------------------- - + --------------------- + ------------------------- +
El | Insertó 10,000 filas con 100,000 bytes de datos cada una | 135005 | 135017 |
El | Se actualizaron todas las filas a datos de imagen de 10,000 bytes | 31251 | 135012 |
El | Reorganizar | 23687 | 25629 |
El | Soltar y volver a agregar datos de imagen | 13485 | 13489 |
+ ------------------------------------------------- - + --------------------- + ------------------------- +
Martin Smith
fuente
1
O si la tabla es grande, BCP elimina los datos y luego BULK INSERT vuelve a colocarlos durante la ventana de mantenimiento.
Kin Shah
6

Tratar

ALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF)

Esto recrea el índice agrupado, por lo que necesitará espacio adicional en su base de datos para completar la operación. Si no tiene espacio adicional porque su disco está lleno, posiblemente podría agregar un nuevo archivo de datos a la base de datos (en un disco diferente) y mover la tabla a él.

También es posible que el índice agrupado se defina con un FILLFACTOR inferior al 100%. Tener el factor de relleno establecido en, por ejemplo, 66%, dejaría 1/3 de cada página de datos vacía para uso futuro. Si este es el problema, puede modificar el factor de relleno usandoALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF, FILLFACTOR=100)

Si recientemente eliminó un campo de longitud variable de la tabla, también podría intentar DBCC CLEANTABLE( Databasename, "MyTableName")

Books online (BOL) tiene un excelente artículo sobre la reconstrucción de índices en http://technet.microsoft.com/en-us/library/ms188388%28v=sql.100%29.aspx

Max Vernon
fuente
2

Asegúrese de que el modo de recuperación de DB es SIMPLE.

alterar la columna como VARBINARY(MAX).

Luego intente copiar los datos en una tabla completamente nueva.

Verifique el nuevo tamaño de la tabla usando sp_spaceused "tablename". Si está satisfecho con el espacio no utilizado de la tabla, compruebe el espacio no utilizado de la base de datos con el mismo comando sin especificar un nombre de tabla. Ese espacio todavía está dentro de los archivos de la base de datos y no se libera al sistema operativo.

Puede soltar la tabla original y cambiar el nombre de la nueva tabla, o hacer lo mismo nuevamente, y usar el nombre de la tabla original si no confía en la operación de cambio de nombre (no confío completamente).

Si esto funciona, el último paso es fácil: sabe cómo reducir los archivos y liberar el espacio no utilizado.

Si hay claves foráneas, registre sus definiciones, suéltelas, realice las tareas que menciono anteriormente y vuelva a crear las claves foráneas después. Por supuesto, esto llevará tiempo y esta operación debe realizarse durante los tiempos de inactividad. Toda esta tarea se puede hacer a través del script también para permitir que se ejecute durante la noche.

Anup Shah
fuente
1

Simplemente crearía una nueva base de datos y copiaría los datos. Debería poder utilizar el asistente de importación / exportación. (Obviamente, una copia de seguridad y una restauración mantendrían el problema). Consulte los resultados de importar los datos. Si todo se ve bien, cambie el nombre de la base de datos original y luego cambie el nombre de la nueva base de datos al nombre que desea usar. (Siempre espero un poco antes de soltar el original, solo para tener una doble verificación en línea).

Por lo que vale, también hemos reclamado el espacio de blob de las bases de datos, si no son demasiado grandes, mediante los siguientes pasos. (Sin embargo, dado que está utilizando SQL Server Express, es posible que no tenga espacio para intentarlo).

  1. Agregue un nuevo archivo al grupo de archivos.
  2. Ejecutar DBCC SHRINKFILE(file, EMPTYFILE). Como está reduciendo el MDF, eventualmente fallará, ya que los metadatos del sistema no se pueden mover. Sin embargo, las asignaciones de blobs vacías no se mueven.
  3. Ejecutar DBCC SHRINKFILE(newfile,EMPTYFILE). Esto moverá los datos hacia atrás, menos el espacio en exceso.
  4. Suelte el nuevo archivo (ahora vacío) del grupo de archivos.

Esto elimina la hinchazón. Debo mencionar que hemos utilizado esta técnica principalmente para crear una base de datos en su mayoría vacía para probar scripts de actualización.

RLF
fuente
-1

Reorganice el índice agrupado: el que tiene los datos en los nodos, así que ... probablemente esté fragmentado.

TomTom
fuente
He intentado ejecutar: ALTER INDEX ALL ON [MyTableName] REORGANIZE;
DermFrench
3
Reconstruirlo;) No reorganizar.
TomTom