Liberare la tabella SQL Server dello spazio inutilizzato


11

Ho una tabella in SQL Server 2012 Express con molto spazio inutilizzato.

Devo liberare spazio nel database.

| NOME | ROWS | RISERVATO | DATI | INDEX_SIZE | NON UTILIZZATO |
| ------------- | -------- | -------------- | ----------- --- | ------------ | -------------- |
| NomeTabella | 158890 | 8928296 KB | 5760944 KB | 2248 KB | 3165104 KB |

Come posso ottenere SQL per rilasciare il 3165104 KB?

Ho già provato:

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) 

Ecco la tabella:

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

L'unica cosa che abbiamo fatto è stata sostituita ScanImagesu ogni riga con un'immagine molto più piccola (ecco quanto spazio c'è inutilizzato).

Risposte:


10

L'unica cosa che abbiamo fatto è stata sostituita ScanImagesu ogni riga con un'immagine molto più piccola (ecco quanto spazio c'è inutilizzato)

Dal fare qualche sperimentazione, il metodo più efficace in termini di spazio sarebbe quello di eliminare l'unità di allocazione e ripopolarla (se si dispone di una finestra di manutenzione per farlo).

Il codice di esempio che ha ottenuto la migliore riduzione dello spazio per me con la struttura della tabella nella domanda è:

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 

Tutto è in una transazione, quindi se la macchina si arresta in modo anomalo verrà ripristinata. Probabilmente potrebbe fare con qualche gestione degli errori o almeno SET XACT_ABORT ON. Ho usato SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;per evitare che si verifichino modifiche simultanee durante o dopo la copia e la perdita.

Il numero di pagine LOB riservate dopo aver ridotto le dimensioni di un imagein tutte le righe era il seguente:

+ ------------------------------------------------- - + --------------------- + ------------------------- +
| Evento | lob_used_page_count | lob_reserved_page_count |
+ ------------------------------------------------- - + --------------------- + ------------------------- +
| Inserite 10.000 righe con 100.000 byte di dati ciascuna | 135005 | 135017 |
| Aggiornato tutte le righe ai dati dell'immagine di 10.000 byte | 31251 | 135012 |
| Riorganizza | 23687 | 25629 |
| Rilasciare e aggiungere nuovamente i dati immagine | 13485 | 13489 |
+ ------------------------------------------------- - + --------------------- + ------------------------- +

1
Oppure, se la tabella è grande, quindi BCP out data e poi BULK INSERT di nuovo - durante la finestra di manutenzione.
Kin Shah,

6

Provare

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

Ciò ricrea l'indice cluster, quindi sarà necessario spazio aggiuntivo nel database per il completamento dell'operazione. Se non si dispone di spazio aggiuntivo perché il disco è pieno, è possibile aggiungere un nuovo file di dati al database (su un altro disco) e spostare la tabella su di esso.

È anche possibile che l'indice cluster sia definito con un FILLFACTOR inferiore al 100%. Se il fattore di riempimento è impostato su, ad esempio il 66%, si lascerebbe vuoto 1/3 di ogni pagina di dati per un utilizzo futuro. Se questo è il problema, è possibile modificare il fattore di riempimento utilizzandoALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF, FILLFACTOR=100)

Se hai recentemente eliminato un campo di lunghezza variabile dalla tabella, puoi anche provare DBCC CLEANTABLE( Databasename, "MyTableName")

La documentazione online (BOL) contiene un ottimo articolo sulla ricostruzione degli indici all'indirizzo http://technet.microsoft.com/en-us/library/ms188388%28v=sql.100%29.aspx


2

Assicurarsi che la modalità di ripristino del DB sia SIMPLE.

modifica la colonna come VARBINARY(MAX).

Quindi prova a copiare i dati in una tabella completamente nuova.

Controllare la nuova dimensione della tabella utilizzando sp_spaceused "tablename". Se si è soddisfatti dello spazio inutilizzato della tabella, controllare lo spazio inutilizzato del database utilizzando lo stesso comando senza specificare un nome di tabella. Quello spazio è ancora all'interno dei file del database e non è rilasciato al sistema operativo.

Puoi eliminare la tabella originale e rinominare la nuova tabella, oppure ripetere la stessa operazione e utilizzare il nome della tabella originale se non ti fidi dell'operazione di ridenominazione (non mi fido completamente).

Se funziona, l'ultimo passaggio è semplice: sai come ridurre i file e liberare spazio inutilizzato.

Se sono presenti chiavi esterne, registrare le loro definizioni, rilasciarle, eseguire le attività menzionate sopra e ricreare le chiavi esterne in seguito. Naturalmente ciò richiederà tempo e questa operazione dovrebbe essere eseguita durante i periodi di inattività. L'intera attività può essere eseguita anche tramite script per consentire l'esecuzione durante la notte.


1

Vorrei solo creare un nuovo database e copiare i dati su di esso. Dovresti essere in grado di utilizzare la procedura guidata di importazione / esportazione. (Ovviamente un backup e un ripristino manterrebbero il problema.) Controlla i risultati dell'importazione dei dati. Se tutto sembra a posto, rinominare il database originale e quindi rinominare il nuovo database con il nome che si desidera utilizzare. (Aspetto sempre un po 'prima di far cadere l'originale, solo per fare un doppio controllo online.)

Per quello che vale, abbiamo anche recuperato lo spazio BLOB dai database, se non sono troppo grandi, con i seguenti passaggi. (Tuttavia, poiché stai usando SQL Server Express, potresti non avere spazio per provare questo.)

  1. Aggiungi un nuovo file al filegroup.
  2. Corri DBCC SHRINKFILE(file, EMPTYFILE). Poiché stai riducendo l'MDF, alla fine fallirà, poiché i metadati di sistema non possono essere spostati. Tuttavia, le allocazioni BLOB vuote non vengono spostate.
  3. Corri DBCC SHRINKFILE(newfile,EMPTYFILE). In questo modo i dati verranno spostati indietro, meno lo spazio in eccesso.
  4. Rilascia il nuovo file (ora vuoto) dal filegroup.

Questo elimina il blob bloat. Dovrei menzionare che abbiamo usato questa tecnica principalmente per creare un database per lo più vuoto per testare gli script di aggiornamento.


-1

Riorganizza l'indice cluster: quello ha i dati sui nodi, quindi ... è probabilmente frammentato.


Ho provato a correre: ALTER INDEX ALL ON [MyTableName] RIORGANIZZA;
DermFrench,

3
Ricostruirlo;) Non riorganizzare.
TomTom,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.