J'utilise le script suivant pour collecter des données à partir de ma base de données qui est SQL Server sur Azure.
-- Script to run against database to gather metrics
CREATE TABLE #SpaceUsed (name sysname,rows bigint,reserved sysname,data sysname,index_size sysname,unused sysname)
DECLARE @Counter int
DECLARE @Max int
DECLARE @Table sysname
SELECT name, IDENTITY(int,1,1) ROWID
INTO #TableCollection
FROM sysobjects
WHERE xtype = 'U'
ORDER BY lower(name)
SET @Counter = 1
SET @Max = (SELECT Max(ROWID) FROM #TableCollection)
WHILE (@Counter <= @Max)
BEGIN
SET @Table = (SELECT name FROM #TableCollection WHERE ROWID = @Counter)
INSERT INTO #SpaceUsed
EXECUTE sp_spaceused @Table
SET @Counter = @Counter + 1
END
SELECT * FROM #SpaceUsed
DROP TABLE #TableCollection
DROP TABLE #SpaceUsed
Une de mes tables est 53 GB in size
, avec 38 GB in data
, 14 GB in unused
. Les index sont 11 MB in size
. Comment puis-je récupérer ce 14 GB that is unused
? Comme c'est dans Azure, l'espace supplémentaire coûte de l'argent.
Après avoir lu divers articles, j'ai essayé ce qui suit pour réduire la taille du tableau.
DBCC DBREINDEX ('myTableName', ' ')
DBCC SHRINKDATABASE (myDatabaseName, 10);
Cependant, une fois ces étapes terminées, la taille de la table reste inchangée. Comment puis-je réduire la taille de la table et de la base de données afin de récupérer l'espace inutilisé?
MISE À JOUR: Il y a 24 colonnes dans le tableau avec 9 des champs étant varchar de grande longueur (> 4000) ou varchar (MAX). 8 autres colonnes sont des types à identifiant unique.
Qu'il s'agisse d'un segment de mémoire ou d'un index clusterisé, vous devriez constater que vous pourrez récupérer de l'espace dans une table en reconstruisant:
ALTER INDEX ALL ON dbo.myTableName REBUILD;
Notez que la récupération d'espace dans une table et la réduction d'une base de données sont deux choses complètement distinctes. La réduction d'une base de données devrait être une chose exceptionnelle - ne réduisez pas une base de données uniquement pour libérer de l'espace disque, car dans la plupart des cas, la base de données devra simplement s'agrandir et réutiliser cet espace de toute façon.
Quant à déterminer comment la table est distribuée, sp_spaceused
est assez inutile, car il ne vous donne qu'un seul élément de ligne avec toutes les données. Tout d'abord, vérifiez si votre table est partitionnée. Vous pouvez le voir rapidement en utilisant:
SELECT COUNT(*)
FROM sys.partitions
WHERE partition_number > 1
AND object_id = OBJECT_ID(N'dbo.myTableName');
Ensuite, voyez comment les données sont réparties sur vos sept index. Si l'un d'entre eux est beaucoup plus grand qu'il ne devrait l'être, vous pouvez essayer de supprimer/recréer (y compris potentiellement supprimer, par exemple, votre colonne XML de la liste INCLUDE
), car il peut y avoir des cas où l'espace LOB pour les lignes que vous avez supprimées ou définies sur NULL
ne sont pas entièrement récupérées, même après une reconstruction.
;WITH x AS
(
SELECT i.name, type = pa.allocation_unit_type_desc, kb = COUNT(*) * 8
FROM sys.indexes AS i
CROSS APPLY sys.dm_db_database_page_allocations(DB_ID(), i.object_id, i.index_id,
NULL, 'LIMITED') AS pa
WHERE i.[object_id] = OBJECT_ID(N'dbo.myTableName')
GROUP BY GROUPING SETS((), (i.name, pa.allocation_unit_type_desc))
)
SELECT name, type, kb,
[%] = CONVERT(decimal(5,2), kb*100.0/(SELECT kb FROM x WHERE name IS NULL))
FROM x
WHERE name IS NOT NULL
ORDER BY name, type;
Si vous souhaitez voir les tailles de ligne individuelles dans la table de base, vous pouvez faire:
SELECT TOP (100) key, rowsize = DATALENGTH(col1) + DATALENGTH(col2) + ...
FROM dbo.myTableName
ORDER BY rowsize DESC;
Si vous en avez qui sont assez volumineuses, vous pouvez vous assurer que vous avez besoin de ces données (sinon, définissez-les sur NULL
, car cela peut être ce qui contribue à votre taille.
Vous devez vérifier le facteur de remplissage sur vos tables et index, pour vous assurer que vous ne réservez pas explicitement beaucoup d'espace sur vos pages. Exécutez la commande suivante:
SELECT t.name as TableName
,COALESCE(i.name,'<no index>') as IndexName
,i.type_desc
,i.Fill_Factor
FROM sys.tables t INNER JOIN sys.indexes i ON t.object_id = i.object_id
;
Le facteur de remplissage indique au moteur SQL la quantité d'espace libre à laisser sur chaque page qu'il crée lorsqu'il remplit une table ou un index. Une fois les pages remplies, SQL ajoutera des informations à la page jusqu'à ce qu'elle soit trop pleine, puis créera une nouvelle page et déplacera une quantité appropriée (généralement environ la moitié) des données vers la nouvelle page.
Si l'un de vos index a un facteur de remplissage faible (inférieur à 75, mais supérieur à 0 (0 signifie en fait remplir à 100%, essentiellement)), il est possible que cela explique une grande quantité d'espace inutilisé dans votre base de données.
Si vous souhaitez modifier le facteur de remplissage de vos index à (par exemple) 90%, vous pouvez utiliser une légère variation sur le ALTER INDEX
commande de la réponse d'Aaron Bertrand:
ALTER INDEX ALL ON dbo.myTableName REBUILD WITH FILLFACTOR = 90;