Eu tenho uma tabela em um banco de dados de produção com um tamanho de 525 GB, dos quais 383 GB não são utilizados:
Gostaria de recuperar parte desse espaço, mas, antes de mexer com o banco de dados de produção, estou testando algumas estratégias em uma tabela idêntica em um banco de dados de teste com menos dados. Esta tabela tem um problema semelhante:
Algumas informações sobre a tabela:
- O fator de preenchimento está definido como 0
- Existem cerca de 30 colunas
- Uma das colunas é um LOB de tipo de imagem e está armazenando arquivos com tamanho variando de algumas KB a várias centenas de MB
- A tabela não possui nenhum índice hipotético associado a ela
O servidor está executando o SQL Server 2017 (RTM-GDR) (KB4505224) - 14.0.2027.2 (X64). O banco de dados está usando o SIMPLEmodelo de recuperação.
Algumas coisas que eu tentei:
- Reconstrução dos índices:
ALTER INDEX ALL ON dbo.MyTable REBUILD. Isso teve um impacto insignificante. - A reorganização dos índices:
ALTER INDEX ALL ON dbo.MyTable REORGANIZE WITH(LOB_COMPACTION = ON). Isso teve um impacto insignificante. Copiou a coluna LOB para outra tabela, soltou a coluna, recriou a coluna e copiou os dados novamente (conforme descrito nesta postagem: Liberando Espaço Não Utilizado na Tabela do SQL Server ). Isso diminuiu o espaço não utilizado, mas parecia convertê-lo em espaço usado:
Utilizou o utilitário bcp para exportar, truncá-la e recarregá-la (conforme descrito nesta postagem: Como liberar o espaço não utilizado para uma tabela ). Isso também reduziu o espaço não utilizado e aumentou o espaço usado em uma extensão semelhante à da imagem acima.
- Embora não seja recomendado, tentei os comandos DBCC SHRINKFILE e DBCC SHRINKDATABASE, mas eles não tiveram nenhum impacto no espaço não utilizado.
- Correr
DBCC CLEANTABLE('myDB', 'dbo.myTable')não fez diferença - Eu tentei todas as opções acima, mantendo os tipos de dados de imagem e texto e depois de alterá-los para varbinary (max) e varchar (max).
- Tentei importar os dados para uma nova tabela em um banco de dados novo, e isso também converteu apenas o espaço não utilizado em espaço usado. Descrevi os detalhes dessa tentativa neste post .
Eu não quero fazer essas tentativas no banco de dados de produção se estes são os resultados que posso esperar, então:
- Por que o espaço não utilizado está sendo convertido em espaço usado após algumas dessas tentativas? Sinto que não tenho uma boa compreensão do que está acontecendo sob o capô.
- Há mais alguma coisa que eu possa fazer para diminuir o espaço não utilizado sem aumentar o espaço usado?
EDIT: Aqui está o relatório de uso de disco e script para a tabela:
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
Aqui estão os resultados da execução dos comandos na resposta de Max Vernon:
╔════════════╦═══════════╦════════════╦═════════════════╦══════════════════════╦════════════════════╗
║ TotalBytes ║ FreeBytes ║ TotalPages ║ TotalEmptyPages ║ PageBytesFreePercent ║ UnusedPagesPercent ║
╠════════════╬═══════════╬════════════╬═════════════════╬══════════════════════╬════════════════════╣
║ 9014280192║ 8653594624║ 1100376║ 997178 ║ 95.998700 ║ 90.621500 ║
╚════════════╩═══════════╩════════════╩═════════════════╩══════════════════════╩════════════════════╝
╔═════════════╦═══════════════════╦════════════════════╗
║ ObjectName ║ ReservedPageCount ║ UsedPageCount ║
╠═════════════╬═══════════════════╬════════════════════╣
║ dbo.MyTable ║ 5109090 ║ 2850245 ║
╚═════════════╩═══════════════════╩════════════════════╝
ATUALIZAR:
Executei o seguinte, conforme sugerido por Max Vernon:
DBCC UPDATEUSAGE (N'<database_name>', N'<table_name>');
E aqui estava a saída:
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.
Isso atualizou o uso do disco para a tabela:
E o uso geral do disco:
Portanto, parece que o problema foi que o uso do disco, conforme rastreado pelo SQL Server, ficou descontrolado com o uso real do disco. Considerarei esse problema resolvido, mas eu estaria interessado em saber por que isso teria acontecido em primeiro lugar!
DBCC CHECKDB? Você já pensou em se afastando dos tipos de dados obsoletos , texte image? Eles podem estar contribuindo para as estatísticas impróprias.





