Ho una tabella in un database di produzione che ha una dimensione di 525 GB, di cui 383 GB non utilizzati:
Vorrei recuperare un po 'di questo spazio, ma, prima di fare confusione con il DB di produzione, sto testando alcune strategie su una tabella identica in un DB di test con meno dati. Questa tabella presenta un problema simile:
Alcune informazioni sulla tabella:
- Il fattore di riempimento è impostato su 0
- Ci sono circa 30 colonne
- Una delle colonne è un LOB di tipo image e contiene file di dimensioni variabili da pochi KB a diverse centinaia di MB
- Alla tabella non sono associati indici ipotetici
Il server esegue SQL Server 2017 (RTM-GDR) (KB4505224) - 14.0.2027.2 (X64). Il database utilizza il SIMPLE
modello di recupero.
Alcune cose che ho provato:
- Ricostruire gli indici:
ALTER INDEX ALL ON dbo.MyTable REBUILD
. Ciò ha avuto un impatto trascurabile. - Riorganizzazione degli indici:
ALTER INDEX ALL ON dbo.MyTable REORGANIZE WITH(LOB_COMPACTION = ON)
. Ciò ha avuto un impatto trascurabile. Copiato la colonna LOB in un'altra tabella, trascinata la colonna, ricreata la colonna e copiato nuovamente i dati (come indicato in questo post: Liberare la tabella SQL Server dello spazio inutilizzato ). Ciò ha ridotto lo spazio inutilizzato, ma sembrava convertirlo in spazio usato:
Utilizzato l'utilità bcp per esportare la tabella, troncarla e ricaricarla (come indicato in questo post: Come liberare lo spazio inutilizzato per una tabella ). Ciò ha anche ridotto lo spazio inutilizzato e aumentato lo spazio utilizzato in misura simile all'immagine sopra.
- Anche se non è raccomandato, ho provato i comandi DBCC SHRINKFILE e DBCC SHRINKDATABASE, ma non hanno avuto alcun impatto sullo spazio inutilizzato.
- Correre
DBCC CLEANTABLE('myDB', 'dbo.myTable')
non ha fatto differenza - Ho provato tutto quanto sopra sia mantenendo i tipi di dati di immagine e testo e dopo aver modificato i tipi di dati in varbinary (max) e varchar (max).
- Ho provato a importare i dati in una nuova tabella in un nuovo database e anche questo ha convertito lo spazio non utilizzato in spazio utilizzato. Ho delineato i dettagli di questo tentativo in questo post .
Non voglio fare questi tentativi sul DB di produzione se questi sono i risultati che posso aspettarmi, quindi:
- Perché lo spazio inutilizzato viene appena convertito in spazio utilizzato dopo alcuni di questi tentativi? Mi sento come se non avessi una buona comprensione di ciò che sta accadendo sotto il cofano.
- C'è qualcos'altro che posso fare per ridurre lo spazio inutilizzato senza aumentare lo spazio utilizzato?
EDIT: ecco il rapporto sull'utilizzo del disco e lo script per la tabella:
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
Ecco i risultati dell'esecuzione dei comandi nella risposta di Max Vernon:
╔════════════╦═══════════╦════════════╦═════════════════╦══════════════════════╦════════════════════╗
║ TotalBytes ║ FreeBytes ║ TotalPages ║ TotalEmptyPages ║ PageBytesFreePercent ║ UnusedPagesPercent ║
╠════════════╬═══════════╬════════════╬═════════════════╬══════════════════════╬════════════════════╣
║ 9014280192║ 8653594624║ 1100376║ 997178 ║ 95.998700 ║ 90.621500 ║
╚════════════╩═══════════╩════════════╩═════════════════╩══════════════════════╩════════════════════╝
╔═════════════╦═══════════════════╦════════════════════╗
║ ObjectName ║ ReservedPageCount ║ UsedPageCount ║
╠═════════════╬═══════════════════╬════════════════════╣
║ dbo.MyTable ║ 5109090 ║ 2850245 ║
╚═════════════╩═══════════════════╩════════════════════╝
AGGIORNARE:
Ho eseguito quanto segue come suggerito da Max Vernon:
DBCC UPDATEUSAGE (N'<database_name>', N'<table_name>');
Ed ecco l'output:
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.
Ciò ha aggiornato l'utilizzo del disco per la tabella:
E l'utilizzo complessivo del disco:
Quindi, sembra che il problema sia che l'utilizzo del disco, come monitorato da SQL Server, è diventato completamente fuori sincrono rispetto all'utilizzo effettivo del disco. Considererò questo problema risolto, ma sarei interessato a sapere perché questo sarebbe successo in primo luogo!
DBCC UPDATEUSAGE
aggiornato lo spazio inutilizzato e il conteggio delle pagine inutilizzate. Sembra che l'utilizzo del disco e le informazioni sulla pagina segnalate da SQL Server siano estremamente non sincronizzate: ho aggiornato il mio post con i dettagli. Sono curioso di sapere come sarebbe potuto succedere in primo luogo, ma almeno il problema è stato riscontrato. Grazie per tutto il tuo aiuto, lo apprezzo davvero!