Taille de la base de données - MDF trop volumineux?

10

Je gère une base de données SQL Server 2005 qui héberge environ 2,9 To de données (2 x 1,45 To - J'ai un schéma RAW et un schéma ANALYSIS donc en gros deux copies des données ingérées). Le modèle de récupération est SIMPLE et .ldfest à 6 Go.

Pour une raison quelconque, le .mdfest de 7,5 To. Maintenant, il n'y a peut-être que 2-3 colonnes supplémentaires dans les tables d'ANALYSE et pas beaucoup de NVARCHAR(MAX)colonnes qui, d'après ce que j'ai (peut-être mal compris - corrigez-moi si je me trompe), peut être à l'origine d'une allocation d'espace supplémentaire. C'est après avoir réduit la base de données tout à l'heure - c'était à ~ 9 To avant cela. Des pensées?

Et, s'il vous plaît, faites-moi savoir si vous avez des questions supplémentaires - Je suis très nouveau dans les efforts d'administration et d'optimisation de la base de données (je ne fais généralement pas ce côté du travail :)).

Merci beaucoup!

Andrija

Andrija_Bgd
la source
Merci Marc - de toute façon, je peux déplacer cette question là ou dois-je re-poster?
Cheers - comme vous pouvez probablement le deviner, je suis nouveau ici :)

Réponses:

11

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]CHARplutô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_spaceusedexé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.objectset sys.dm_db_partition_statsutilisé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:

  1. Ce qui n'est alloué à rien (cela apparaît dans le premier jeu de résultats sp_spaceusedsans objet spécifié)
  2. Ce qui est alloué à un objet (réservé) mais non utilisé actuellement (cela apparaît dans le compte "inutilisé" dans sp_spaceusedla sortie de.
  3. 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 ( TEXTcolonnes,[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.

David Spillett
la source
David - merci beaucoup pour la réponse détaillée! J'analyse la base de données en ce moment et vos réponses et celles de Kenneth ont été d'une immense aide dans ma compréhension des facteurs influençant la taille de la base de données. Je suis toujours préoccupé par l'efficacité (à la fois en ce qui concerne l'ingestion et l'utilisation des données) et les informations que vous avez fournies ont été inestimables!
Andrija_Bgd
6

Essayez d'exécuter sp_spaceusedsur votre base de données. À titre d'exemple, il renvoie:

reserved           data               index_size         unused
------------------ ------------------ ------------------ ------------------
6032 KB            2624 KB            1664 KB            1744 KB

Pour l'exécuter sur la base de USEdonnées, exécutez simplement la base de données sp_spaceused.

S'il montre encore beaucoup d'espace inutilisé, vous pouvez réessayer le rétrécissement. Parfois, je trouve que cela prend plusieurs essais. Parfois aussi, je trouve qu'il est préférable de réduire le fichier individuel plutôt que la base de données dans son ensemble. Cependant, ce que vous pouvez trouver, c'est que vous avez 2,9 To de données et encore 4 + Tb d'index, auquel cas la 7,5 To est assez raisonnable. Si vous voulez avoir une idée de la quantité d'espace (données et index) de chaque table, vous pouvez également exécuter sp_spaceusedau niveau de la table. Vous pouvez l'exécuter sur toutes les tables de la base de données à l'aide de la commande suivante:

EXEC sp_msforeachtable 'EXEC sp_spaceused [?];'

Bien que l'avertissement juste sp_msforeachtable soit non documenté, non pris en charge et connu pour manquer des tables. D'un autre côté, j'ai eu pas mal de chance avec.

Cela étant dit, votre base de données DEVRAIT avoir un certain pourcentage d'espace libre en fonction de votre croissance attendue. Fondamentalement, vous voulez vous assurer d'avoir de l'espace pour une croissance de 6 mois à quelques années. Vous voudrez également vérifier vos autogrowthparamètres pour vous assurer qu'ils sont adaptés à votre situation. Etant donné la taille de votre base de données, vous ne voulez PAS utiliser de% autogrowth.

Kenneth Fisher
la source
Je vous remercie! J'ai utilisé sp_spaceused et il semble que les données réelles occupent en fait la quantité d'espace indiquée, aussi étrange que cela puisse paraître pour moi étant donné la taille réelle des fichiers plats qui ont été chargés ... Les indices sont petits (je n'ai pas '' t créé des supplémentaires car ils auraient été plus un obstacle que d'aide dans mon cas), donc je suppose que ce sont juste les tables qui sont grandes ... Merci mille fois pour votre aide!
Andrija_Bgd
Les bases de données prennent plus d'espace que les fichiers plats. Il y a une certaine quantité de surcharge pour les structures de lignes et de tables et une certaine quantité de déchets en raison de la structure de la page.
Kenneth Fisher
-1

À l'aide de SQL Management Studio, 1.Cliquez avec le bouton droit sur la base de données, puis 2.Cliquez sur Tâches-> Rétrécir -> Fichiers

Vous verrez une boîte de dialogue qui affiche: a. Espace actuellement alloué b. Espace libre disponible + (% gratuit)

Si votre% gratuit est supérieur à 50%, vous pouvez envisager de réduire le fichier. J'ai vu ce succès atteindre 90%. Si je décide de réduire le fichier, je le règle généralement sur 2 ou 3 concerts de plus que l'espace alloué actuel. La plupart de mes bases de données ont moins de 50 Go. Donc, si vous avez un fichier beaucoup plus volumineux, vous pouvez en faire 10 gigaoctets. Je ne m'inquiète généralement de la réduction que si je vais déplacer la base de données vers un autre serveur, vous pouvez tout lire sur les problèmes de réduction sur n'importe quelle page SQL.

Clark Vera
la source