Liberando tabela do SQL Server de espaço não utilizado

11

Eu tenho uma tabela no SQL Server 2012 Express com muito espaço não utilizado.

Eu preciso liberar espaço no banco de dados.

| NOME Linhas | RESERVADO | DADOS INDEX_SIZE | NÃO UTILIZADO |
| ------------- | -------- | -------------- | ----------- --- | ------------ | -------------- |
| MyTableName | 158890 8928296 KB | 5760944 KB | 2248 KB | 3165104 KB |

Como obtenho o SQL para liberar o 3165104KB?

Eu já tentei:

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) 

Aqui está a tabela:

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

A única coisa que fizemos é substituída ScanImageem cada linha por uma imagem muito menor (é a quantidade de espaço não utilizado disponível).

DermFrench
fonte

Respostas:

10

A única coisa que fizemos é substituída ScanImageem cada linha por uma imagem muito menor (é a quantidade de espaço não utilizado disponível)

Ao fazer algumas experiências, o método com mais espaço efetivo seria descartar a unidade de alocação e preenchê-la novamente (se você tiver uma janela de manutenção para fazer isso).

O código de exemplo que obteve a melhor redução de espaço para mim com a estrutura da tabela na pergunta é:

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 

Tudo está em uma transação, portanto, se a máquina travar, ela será revertida. Provavelmente poderia fazer com algum tratamento de erro ou pelo menos SET XACT_ABORT ON. Eu costumava SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;impedir que qualquer modificação simultânea acontecesse durante ou após a cópia e se perdesse.

O número de páginas LOB reservadas após a redução do tamanho de um imageem todas as linhas foi o seguinte:

+ ------------------------------------------------- - + --------------------- + ------------------------- +
| Evento lob_used_page_count | lob_reserved_page_count |
+ ------------------------------------------------- - + --------------------- + ------------------------- +
| 10.000 linhas inseridas com dados de 100.000 bytes cada | 135005 135017
| Atualizadas todas as linhas para dados de imagem de 10.000 bytes | 31251 135012
| Reorganizar | 23687 25629
| Solte e adicione novamente dados de imagem | 13485 13489
+ ------------------------------------------------- - + --------------------- + ------------------------- +
Martin Smith
fonte
1
Ou, se a tabela for grande, faça a saída dos dados do BCP e insira novamente o BULK INSERT - durante a janela de manutenção.
quer
6

Experimentar

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

Isso recria o índice em cluster, portanto, você precisará de espaço extra no banco de dados para que a operação seja concluída. Se você não tiver espaço extra porque seu disco está cheio, você poderá adicionar um novo arquivo de dados ao banco de dados (em um disco diferente) e mover a tabela para ele.

Também é possível que o índice clusterizado seja definido com um FILLFACTOR menor que 100%. Ter o fator de preenchimento definido como, por exemplo, 66%, deixaria 1/3 de cada página de dados em branco para uso futuro. Se esse for o problema, você poderá modificar o fator de preenchimento usandoALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF, FILLFACTOR=100)

Se você soltou recentemente um campo de tamanho variável da tabela, também pode tentar DBCC CLEANTABLE( Databasename, "MyTableName")

O Books Online (BOL) tem um ótimo artigo sobre a reconstrução de índices em http://technet.microsoft.com/en-us/library/ms188388%28v=sql.100%29.aspx

Max Vernon
fonte
2

Verifique se o modo de recuperação do banco de dados está SIMPLE.

altere a coluna como VARBINARY(MAX).

Em seguida, tente copiar os dados em uma tabela completamente nova.

Verifique o novo tamanho da tabela usando sp_spaceused "tablename". Se você estiver satisfeito com o espaço não utilizado da tabela, verifique o espaço não utilizado do banco de dados usando o mesmo comando sem especificar um nome de tabela. Esse espaço ainda está nos arquivos do banco de dados e não é liberado para o sistema operacional.

Você pode soltar a tabela original e renomear a nova tabela, ou fazer a mesma coisa novamente e usar o nome da tabela original se não confiar na operação de renomeação (não confio completamente).

Se isso funcionar, o último passo é fácil: você sabe como reduzir arquivos e liberar espaço não utilizado.

Se houver chaves estrangeiras, registre suas definições, descarte-as, execute as tarefas mencionadas acima e recrie as chaves estrangeiras posteriormente. Obviamente, isso levará tempo e essa operação deve ser feita durante os períodos de folga. Toda essa tarefa pode ser realizada por meio de script para permitir que ela seja executada da noite para o dia.

Anup Shah
fonte
1

Gostaria apenas de criar um novo banco de dados e copiar os dados para ele. Você deve poder usar o assistente de importação / exportação. (Obviamente, um backup e restauração manteriam o problema.) Confira os resultados da importação dos dados. Se tudo parecer bom, renomeie o banco de dados original e renomeie o novo banco de dados para o nome que você deseja usar. (Eu sempre espero um pouco antes de largar o original, apenas para ter uma verificação dupla online.)

Quanto vale a pena, também recuperamos o espaço de blob dos bancos de dados, se eles não forem muito grandes, pelas etapas a seguir. (No entanto, como você está usando o SQL Server Express, talvez você não tenha espaço para tentar isso).

  1. Adicione um novo arquivo ao grupo de arquivos.
  2. Corra DBCC SHRINKFILE(file, EMPTYFILE). Como você está reduzindo o MDF, ele eventualmente falhará, pois os metadados do sistema não podem ser movidos. No entanto, as alocações de blob vazias não são movidas.
  3. Corra DBCC SHRINKFILE(newfile,EMPTYFILE). Isso moverá os dados de volta, menos o espaço em excesso.
  4. Solte o novo arquivo (agora vazio) do grupo de arquivos.

Isso elimina o inchaço das bolhas. Devo mencionar que usamos essa técnica principalmente para criar um banco de dados quase vazio para testar scripts de atualização.

RLF
fonte
-1

Reorganize o índice em cluster - esse possui os dados nos nós, portanto ... provavelmente está fragmentado.

TomTom
fonte
Eu tentei executar: ALTER INDEX ALL ON [MyTableName] REORGANIZE;
DermFrench 28/10
3
Reconstrua;) Não reorganize.
TomTom