J'ai une table dans une base de données de production d'une taille de 525 Go, dont 383 Go inutilisés:
Je voudrais récupérer une partie de cet espace, mais, avant de jouer avec la base de données de production, je teste certaines stratégies sur une table identique dans une base de données de test avec moins de données. Ce tableau a un problème similaire:
Quelques informations sur la table:
- Le facteur de remplissage est défini sur 0
- Il y a environ 30 colonnes
- L'une des colonnes est un LOB de type image, et il stocke des fichiers dont la taille varie de quelques Ko à plusieurs centaines de Mo
- La table n'a aucun index hypothétique qui lui est associé
Le serveur exécute SQL Server 2017 (RTM-GDR) (KB4505224) - 14.0.2027.2 (X64). La base de données utilise le SIMPLE
modèle de récupération.
Certaines choses que j'ai essayées:
- La reconstruction des index:
ALTER INDEX ALL ON dbo.MyTable REBUILD
. Cela a eu un impact négligeable. - Réorganisant les indices:
ALTER INDEX ALL ON dbo.MyTable REORGANIZE WITH(LOB_COMPACTION = ON)
. Cela a eu un impact négligeable. Copié la colonne LOB dans une autre table, supprimé la colonne, recréé la colonne et recopié les données (comme indiqué dans cet article: Libération de l'espace SQL Server Table SQL Server ). Cela a diminué l'espace inutilisé, mais il semblait simplement le convertir en espace utilisé:
Utilisé l'utilitaire bcp pour exporter la table, la tronquer et la recharger (comme indiqué dans cet article: Comment libérer l'espace inutilisé pour une table ). Cela a également réduit l'espace inutilisé et augmenté l'espace utilisé dans une mesure similaire à l'image ci-dessus.
- Même si ce n'est pas recommandé, j'ai essayé les commandes DBCC SHRINKFILE et DBCC SHRINKDATABASE, mais elles n'ont eu aucun impact sur l'espace inutilisé.
- La course
DBCC CLEANTABLE('myDB', 'dbo.myTable')
n'a pas fait de différence - J'ai essayé tout ce qui précède à la fois tout en conservant les types de données image et texte et après avoir changé les types de données en varbinary (max) et varchar (max).
- J'ai essayé d'importer les données dans une nouvelle table dans une nouvelle base de données, et cela n'a également converti que l'espace inutilisé en espace utilisé. J'ai décrit les détails de cette tentative dans cet article .
Je ne veux pas faire ces tentatives sur la base de données de production si ce sont les résultats auxquels je peux m'attendre, donc:
- Pourquoi l'espace inutilisé est-il simplement converti en espace utilisé après certaines de ces tentatives? J'ai l'impression de ne pas bien comprendre ce qui se passe sous le capot.
- Puis-je faire autre chose pour réduire l'espace inutilisé sans augmenter l'espace utilisé?
EDIT: voici le rapport d'utilisation du disque et le script de la table:
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
Voici les résultats de l'exécution des commandes dans la réponse de Max Vernon:
╔════════════╦═══════════╦════════════╦═════════════════╦══════════════════════╦════════════════════╗
║ TotalBytes ║ FreeBytes ║ TotalPages ║ TotalEmptyPages ║ PageBytesFreePercent ║ UnusedPagesPercent ║
╠════════════╬═══════════╬════════════╬═════════════════╬══════════════════════╬════════════════════╣
║ 9014280192║ 8653594624║ 1100376║ 997178 ║ 95.998700 ║ 90.621500 ║
╚════════════╩═══════════╩════════════╩═════════════════╩══════════════════════╩════════════════════╝
╔═════════════╦═══════════════════╦════════════════════╗
║ ObjectName ║ ReservedPageCount ║ UsedPageCount ║
╠═════════════╬═══════════════════╬════════════════════╣
║ dbo.MyTable ║ 5109090 ║ 2850245 ║
╚═════════════╩═══════════════════╩════════════════════╝
MISE À JOUR:
J'ai exécuté ce qui suit comme suggéré par Max Vernon:
DBCC UPDATEUSAGE (N'<database_name>', N'<table_name>');
Et voici la sortie:
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.
Cela a mis à jour l'utilisation du disque pour la table:
Et l'utilisation globale du disque:
Ainsi, il semble que le problème était que l'utilisation du disque, telle que suivie par SQL Server, soit complètement désynchronisée avec l'utilisation réelle du disque. Je considérerai ce problème résolu, mais je serais intéressé de savoir pourquoi cela se serait produit en premier lieu!
DBCC UPDATEUSAGE
mis à jour l'espace et le nombre de pages inutilisés. Il semble que l'utilisation du disque et les informations de page signalées par SQL Server soient extrêmement désynchronisées - j'ai mis à jour mon message avec les détails. Je suis curieux de savoir comment cela aurait pu se produire en premier lieu, mais au moins le problème a été trouvé. Merci pour toute votre aide, je l'apprécie vraiment!