Dans vos estimations de taille, avez-vous pris en compte la quantité d'espace occupée par les index? De plus, si vous avez des champs de texte définis sur plusieurs octets ( N[VAR]CHAR
plutôt que [VAR]CHAR
) et que les fichiers d'entrée sont en UTF-8 ou en un octet par caractère, cela augmentera vos besoins de stockage jusqu'à un facteur deux. De plus, n'oubliez pas que si vous avez une clé / un index en cluster sur une table, sa taille affecte tous les autres index de la table car ils incluent la valeur de la clé en cluster pour chaque ligne (afin de donner un exemple extrême si une table a un NCHAR (10 ) où un INT ferait et c'est votre clé / index clusterisé, vous utilisez non seulement 16 octets supplémentaires par ligne dans les pages de données, mais vous gaspillez également 16 octets par ligne dans tous les autres index de cette table ) .
En outre, un certain espace sera alloué mais inutilisé, soit parce que le moteur de base de données a laissé un certain espace alloué après les suppressions afin qu'il puisse être réutilisé rapidement pour les nouvelles données dans cette table ou parce que le modèle d'insertions et de suppressions n'a laissé qu'une partie de nombreuses pages plein.
Tu peux courir:
SELECT o.name
, SUM(ps.reserved_page_count)/128.0 AS ReservedMB
, SUM(ps.used_page_count)/128.0 AS UsedMB
, SUM(ps.reserved_page_count-ps.used_page_count)/128.0 AS DiffMB
FROM sys.objects o
JOIN sys.dm_db_partition_stats ps ON o.object_id = ps.object_id
WHERE OBJECTPROPERTYEX(o.object_id, 'IsMSShipped') = 0
GROUP BY o.name
ORDER BY SUM(ps.reserved_page_count) DESC
pour voir rapidement quelles tables occupent de l'espace.
Également EXEC sp_spaceused
exécuté dans cette base de données renverra deux jeux de résultats. Le premier répertorie l'espace total alloué dans le système de fichiers pour les fichiers de données et la quantité non allouée, le second répertorie la quantité d'espace alloué utilisée pour les pages de données, les pages d'index ou actuellement inutilisée.
sp_spaceused
retournera également l'espace utilisé par un objet donné, vous pouvez donc le boucler pour construire une table pour l'analyse:
-- TEMP TABLES FOR ANALYSIS
CREATE TABLE #tTables (sName NVARCHAR(MAX), iRows BIGINT, iReservedKB BIGINT, iDataKB BIGINT, iIndexKB BIGINT, iUnusedKB BIGINT)
CREATE TABLE #tTmp (sName NVARCHAR(MAX), iRows BIGINT, sReservedKB NVARCHAR(MAX), sDataKB NVARCHAR(MAX), sIndexKB NVARCHAR(MAX), sUnusedKB NVARCHAR(MAX))
-- COLLECT SPACE USE PER TABLE
EXEC sp_msforeachtable 'INSERT #tTmp EXEC sp_spaceused [?];'
-- CONVERT NUMBER-AS-TEXT COLUMNS TO NUMBER TYPES FOR EASIER ANALYSIS
INSERT #tTables SELECT sName, iRows
, CAST(REPLACE(sReservedKB, ' KB', '') AS BIGINT)
, CAST(REPLACE(sDataKB , ' KB', '') AS BIGINT)
, CAST(REPLACE(sIndexKB , ' KB', '') AS BIGINT)
, CAST(REPLACE(sUnusedKB , ' KB', '') AS BIGINT)
FROM #tTmp
DROP TABLE #tTmp
-- DO SOME ANALYSIS
SELECT sName='TOTALS', iRows=SUM(iRows), iReservedKB=SUM(iReservedKB), iDataKB=SUM(iDataKB), iIndexKB=SUM(iIndexKB), iUnusedKB=SUM(iUnusedKB) FROM #tTables ORDER BY sName
SELECT * FROM #tTables ORDER BY iReservedKB DESC
-- CLEAN UP
DROP TABLE #tTables
Le code ci-dessus affichera toutes les tailles de tableau dans une liste, plus une seule ligne pour les totaux. Si nécessaire, vous pouvez utiliser les différentes vues système (similaires sys.objects
et sys.dm_db_partition_stats
utilisées dans la première requête ci-dessus, voir http://technet.microsoft.com/en-us/library/ms177862.aspx pour beaucoup plus de détails) pour obtenir plus de détails tels que l'espace utilisé par chaque index.
Il existe trois classes d'espace inutilisé dans un fichier de données:
- Ce qui n'est alloué à rien (cela apparaît dans le premier jeu de résultats
sp_spaceused
sans objet spécifié)
- Ce qui est alloué à un objet (réservé) mais non utilisé actuellement (cela apparaît dans le compte "inutilisé" dans
sp_spaceused
la sortie de.
- Cela a été verrouillé dans des pages partiellement utilisées (cela semblera être utilisé car tout est alloué en morceaux d'une seule page, une page faisant 8 192 octets). C'est plus difficile à détecter / calculer. Cela est dû à un mélange de deux facteurs:
- Séparer les pages. Au fur et à mesure que des données sont ajoutées, vous vous retrouvez souvent avec des pages partiellement vides (le moteur de stockage peut toujours normaliser le contenu de la page, mais cela serait très inefficace), et comme les lignes sont supprimées, le contenu de la page n'est pas automatiquement compressé (encore une fois, il pourrait l'être, mais le supplément La charge d'E / S est généralement loin d'en valoir la peine).
- Le moteur de stockage ne divisera pas une ligne sur plusieurs pages (ceci avec la taille de la page d'où vient la limite de 8 192 octets par ligne). Si vos lignes sont de taille fixe et prennent 1 100 octets chacune, vous allez "gaspiller" au moins 492 octets de chaque bloc de données alloué à cette table (7 lignes prennent 7 700 octets et un 8ème ne convient pas pour que les octets restants gagnent " t être utilisé). Plus les rangées sont larges, pire cela peut être. Les tables / index avec des lignes de longueur variable (qui sont beaucoup plus courantes que celles de longueur complètement fixe) sont généralement mieux (mais sont moins faciles à calculer).
Une autre mise en garde ici concerne les gros objets ( TEXT
colonnes,[N]VARCHAR(MAX)
valeurs au-dessus d'une certaine taille et ainsi de suite) car ils sont placés hors page, en prenant juste 8 octets dans les données de la ligne principale pour contenir un pointeur vers les données ailleurs), ce qui peut briser la limite de 8192 octets par ligne.
tl; dr: L' estimation des tailles de base de données attendues peut être beaucoup plus complexe qu'il n'est naturel de le supposer initialement.