Tengo una tabla en una base de datos de producción que tiene un tamaño de 525 GB, de los cuales 383 GB no se utilizan:
Me gustaría recuperar parte de este espacio, pero, antes de jugar con el DB de producción, estoy probando algunas estrategias en una tabla idéntica en un DB de prueba con menos datos. Esta tabla tiene un problema similar:
Alguna información sobre la tabla:
- El factor de relleno se establece en 0
- Hay alrededor de 30 columnas
- Una de las columnas es una imagen de tipo LOB, y almacena archivos que varían en tamaño desde unos pocos KB hasta varios cientos de MB
- La tabla no tiene ningún índice hipotético asociado.
El servidor ejecuta SQL Server 2017 (RTM-GDR) (KB4505224) - 14.0.2027.2 (X64). La base de datos está utilizando el SIMPLE
modelo de recuperación.
Algunas cosas que he probado:
- La reconstrucción de los índices:
ALTER INDEX ALL ON dbo.MyTable REBUILD
. Esto tuvo un impacto insignificante. - La reorganización de los índices:
ALTER INDEX ALL ON dbo.MyTable REORGANIZE WITH(LOB_COMPACTION = ON)
. Esto tuvo un impacto insignificante. Copié la columna LOB en otra tabla, soltó la columna, volvió a crear la columna y volvió a copiar los datos (como se describe en esta publicación: Liberación de la tabla de SQL Server del espacio no utilizado ). Esto disminuyó el espacio no utilizado, pero parecía convertirlo en espacio usado:
Usó la utilidad bcp para exportar la tabla, truncarla y volver a cargarla (como se describe en esta publicación: Cómo liberar el espacio no utilizado para una tabla ). Esto también redujo el espacio no utilizado y aumentó el espacio utilizado en un grado similar al de la imagen de arriba.
- Aunque no se recomienda, probé los comandos DBCC SHRINKFILE y DBCC SHRINKDATABASE, pero no tuvieron ningún impacto en el espacio no utilizado.
- Correr
DBCC CLEANTABLE('myDB', 'dbo.myTable')
no hizo la diferencia - He intentado todo lo anterior mientras mantengo los tipos de datos de imagen y texto y después de cambiar los tipos de datos a varbinary (max) y varchar (max).
- Intenté importar los datos a una nueva tabla en una nueva base de datos, y esto también solo convirtió el espacio no utilizado en espacio usado. Describí los detalles de este intento en esta publicación .
No quiero hacer estos intentos en la base de datos de producción si estos son los resultados que puedo esperar, así que:
- ¿Por qué el espacio no utilizado se está convirtiendo en espacio usado después de algunos de estos intentos? Siento que no entiendo bien lo que sucede debajo del capó.
- ¿Hay algo más que pueda hacer para disminuir el espacio no utilizado sin aumentar el espacio utilizado?
EDITAR: Aquí está el informe de uso del disco y la secuencia de comandos para la tabla:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[MyTable](
[Column1] [int] NOT NULL,
[Column2] [int] NOT NULL,
[Column3] [int] NOT NULL,
[Column4] [bit] NOT NULL,
[Column5] [tinyint] NOT NULL,
[Column6] [datetime] NULL,
[Column7] [int] NOT NULL,
[Column8] [varchar](100) NULL,
[Column9] [varchar](256) NULL,
[Column10] [int] NULL,
[Column11] [image] NULL,
[Column12] [text] NULL,
[Column13] [varchar](100) NULL,
[Column14] [varchar](6) NULL,
[Column15] [int] NOT NULL,
[Column16] [bit] NOT NULL,
[Column17] [datetime] NULL,
[Column18] [varchar](50) NULL,
[Column19] [varchar](50) NULL,
[Column20] [varchar](60) NULL,
[Column21] [varchar](20) NULL,
[Column22] [varchar](120) NULL,
[Column23] [varchar](4) NULL,
[Column24] [varchar](75) NULL,
[Column25] [char](1) NULL,
[Column26] [varchar](50) NULL,
[Column27] [varchar](128) NULL,
[Column28] [varchar](50) NULL,
[Column29] [int] NULL,
[Column30] [text] NULL,
CONSTRAINT [PK] PRIMARY KEY CLUSTERED
(
[Column1] ASC,
[Column2] ASC,
[Column3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[MyTable] ADD CONSTRAINT [DF_Column4] DEFAULT (0) FOR [Column4]
GO
ALTER TABLE [dbo].[MyTable] ADD CONSTRAINT [DF_Column5] DEFAULT (0) FOR [Column5]
GO
ALTER TABLE [dbo].[MyTable] ADD CONSTRAINT [DF_Column15] DEFAULT (0) FOR [Column15]
GO
ALTER TABLE [dbo].[MyTable] ADD CONSTRAINT [DF_Column16] DEFAULT (0) FOR [Column16]
GO
Estos son los resultados de ejecutar los comandos en la respuesta de Max Vernon:
╔════════════╦═══════════╦════════════╦═════════════════╦══════════════════════╦════════════════════╗
║ TotalBytes ║ FreeBytes ║ TotalPages ║ TotalEmptyPages ║ PageBytesFreePercent ║ UnusedPagesPercent ║
╠════════════╬═══════════╬════════════╬═════════════════╬══════════════════════╬════════════════════╣
║ 9014280192║ 8653594624║ 1100376║ 997178 ║ 95.998700 ║ 90.621500 ║
╚════════════╩═══════════╩════════════╩═════════════════╩══════════════════════╩════════════════════╝
╔═════════════╦═══════════════════╦════════════════════╗
║ ObjectName ║ ReservedPageCount ║ UsedPageCount ║
╠═════════════╬═══════════════════╬════════════════════╣
║ dbo.MyTable ║ 5109090 ║ 2850245 ║
╚═════════════╩═══════════════════╩════════════════════╝
ACTUALIZAR:
Ejecuté lo siguiente según lo sugerido por Max Vernon:
DBCC UPDATEUSAGE (N'<database_name>', N'<table_name>');
Y aquí estaba el resultado:
DBCC UPDATEUSAGE: Usage counts updated for table 'MyTable' (index 'PK_MyTable', partition 1):
USED pages (LOB Data): changed from (568025) to (1019641) pages.
RSVD pages (LOB Data): changed from (1019761) to (1019763) pages.
Esto actualizó el uso del disco para la tabla:
Y el uso general del disco:
Por lo tanto, parece que el problema fue que el uso del disco según lo rastreado por SQL Server se desincronizó con el uso real del disco. Consideraré este problema resuelto, ¡pero me interesaría saber por qué esto habría sucedido en primer lugar!
DBCC UPDATEUSAGE
actualizó el espacio no utilizado y el número de páginas no utilizadas. Parece que el uso del disco y la información de la página informada por SQL Server estaba extremadamente fuera de sincronización: actualicé mi publicación con los detalles. Tengo curiosidad por saber cómo habría sucedido esto en primer lugar, pero al menos se encontró el problema. Gracias por toda su ayuda, ¡realmente lo aprecio!