Datenbankgröße - MDF zu groß?

10

Ich verwalte eine SQL Server 2005-Datenbank, die ungefähr 2,9 TB Daten hostet (2 x 1,45 TB - Ich habe ein RAW-Schema und ein ANALYSIS-Schema, also im Grunde genommen zwei Kopien der aufgenommenen Daten). Das Wiederherstellungsmodell ist EINFACH und .ldfliegt bei 6 GB.

Aus welchem ​​Grund auch immer, das .mdfist 7,5 TB. Jetzt gibt es nur noch 2-3 zusätzliche Spalten in ANALYSIS-Tabellen und nicht viele NVARCHAR(MAX)Spalten, die nach meinem Verständnis (möglicherweise falsch verstanden - bitte korrigieren Sie mich, wenn ich falsch liege ) zusätzliche Speicherplatzzuweisung verursachen können. Das ist, nachdem die Datenbank gerade verkleinert wurde - vorher waren es ~ 9 TB. Irgendwelche Gedanken?

Und bitte lassen Sie mich wissen, wenn Sie weitere Fragen haben - ich bin sehr neu in der Datenbankverwaltung und -optimierung (normalerweise mache ich diese Seite des Jobs nicht :)).

Danke vielmals!

Andrija

Andrija_Bgd
quelle
Danke Marc - wie kann ich diese Frage dorthin verschieben oder muss ich sie erneut posten?
Prost - wie Sie wahrscheinlich erraten können, bin ich neu hier :)

Antworten:

11

Haben Sie bei Ihren Größenschätzungen den Speicherplatz berücksichtigt, den Indizes belegen? Auch wenn Sie Textfelder haben, die als Multibyte ( N[VAR]CHARanstatt [VAR]CHAR) festgelegt sind und die Eingabedateien UTF-8 oder ein einfaches Byte pro Zeichen sind, werden Ihre Speicheranforderungen um den Faktor zwei erhöht. Denken Sie außerdem daran, dass wenn Sie einen Clustered Key / Index in einer Tabelle haben, die Größe dieses Index alle anderen Indizes in der Tabelle beeinflusst, da sie den Clustered Key-Wert für jede Zeile enthalten (um ein extremes Beispiel zu geben, wenn eine Tabelle eine NCHAR hat (10) ) Taste , wo ein INT tun würde , und das ist Ihre gruppierten Schlüssel / Index Sie sind nicht nur eine zusätzliche 16 Byte pro Zeile in den Datenseiten mit verschwenden Sie auch 16 Byte pro Zeile in das auf dieser Tabelle alle anderen Index ) .

Außerdem wird etwas Speicherplatz zugewiesen, aber nicht verwendet, entweder weil die DB-Engine nach dem Löschen etwas Speicherplatz zugewiesen hat, damit er schnell wieder für neue Daten in dieser Tabelle verwendet werden kann, oder weil das Muster des Einfügens und Löschens viele Seiten nur teilweise zurückgelassen hat voll.

Du kannst rennen:

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

um einen schnellen Überblick darüber zu erhalten, welche Tische Platz beanspruchen.

Auch EXEC sp_spaceusedwird wieder zwei Ergebnismengen innerhalb dieser DB laufen. Der erste listet den gesamten im Dateisystem zugewiesenen Speicherplatz für die Datendateien auf und wie viel davon nicht zugewiesen ist, der zweite listet auf, wie viel des zugewiesenen Speicherplatzes für Datenseiten, für Indexseiten verwendet wird oder derzeit nicht verwendet wird.

sp_spaceused gibt auch den von einem bestimmten Objekt verwendeten Speicherplatz zurück, sodass Sie diesen schleifen können, um eine Tabelle für die Analyse zu erstellen:

-- 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

Der obige Code gibt alle Tabellengrößen in einer Liste sowie eine einzelne Zeile für die Summen aus. Bei Bedarf können Sie die verschiedenen Systemansichten verwenden (wie sys.objectsund sys.dm_db_partition_statsin der ersten Abfrage oben verwendet, siehe http://technet.microsoft.com/en-us/library/ms177862.aspx für weitere Details), um weitere Details zu erhalten, wie z Der von jedem Index verwendete Speicherplatz.


Es gibt drei Klassen von nicht verwendetem Speicherplatz in einer Datendatei:

  1. Das, was nichts zugeordnet ist (dies zeigt in der ersten Ergebnismenge von sp_spaceusedohne angegebenes Objekt)
  2. Das, was einem Objekt zugeordnet ist (reserviert), aber derzeit nicht verwendet wird (dies zeigt sich in der "nicht verwendeten" Anzahl in sp_spaceusedder Ausgabe.
  3. Das ist in teilweise verwendeten Seiten gesperrt (dies wird verwendet, da alles in einzelnen Seitenblöcken zugeordnet ist, wobei eine Seite 8.192 Bytes lang ist). Dies ist schwieriger zu erkennen / zu berechnen. Es ist auf eine Mischung aus zwei Faktoren zurückzuführen:
    • Seiten teilen. Wenn Daten hinzugefügt werden, erhalten Sie häufig teilweise leere Seiten (die Speicher-Engine könnte den Seiteninhalt immer normalisieren, dies wäre jedoch sehr ineffizient), und wenn Zeilen gelöscht werden, wird der Seiteninhalt nicht automatisch gepackt (dies könnte auch der Fall sein) I / O - Last ist in der Regel weit von wert).
    • Die Speicher-Engine teilt eine Zeile nicht auf mehrere Seiten auf (dies zusammen mit der Seitengröße, von der das Limit von 8.192 Byte pro Zeile stammt). Wenn Ihre Zeilen eine feste Größe haben und jeweils 1.100 Bytes benötigen, werden Sie mindestens 492 Bytes jedes dieser Tabelle zugewiesenen Datenblocks "verschwenden" (7 Zeilen benötigen 7.700 Bytes und ein 8. passt nicht, sodass die verbleibenden Bytes gewonnen werden.) nicht verwendet werden). Je breiter die Reihen, desto schlimmer kann dies sein. Tabellen / Indizes mit Zeilen variabler Länge (die weitaus häufiger sind als Zeilen mit vollständig fester Länge) sind im Allgemeinen besser (aber weniger einfach zu berechnen).
      Eine weitere Einschränkung sind große Objekte ( TEXTSpalten,[N]VARCHAR(MAX) Werte über einer bestimmten Größe usw.), wenn sie außerhalb der Seite platziert werden, wobei nur 8 Bytes in den Daten der Hauptzeile benötigt werden, um einen Zeiger auf die Daten an anderer Stelle zu halten), wodurch die Grenze von 8.192 Bytes pro Zeile überschritten werden kann.

tl; dr: Das Schätzen der erwarteten Datenbankgrößen kann viel komplizierter sein, als es zunächst angenommen wird.

David Spillett
quelle
David - vielen Dank für die ausführliche Antwort! Ich analysiere gerade die Datenbank und sowohl Ihre als auch Kenneths Antworten haben mir sehr geholfen, die Faktoren zu verstehen, die die Datenbankgröße beeinflussen. Ich bin immer um Effizienz bemüht (sowohl bei der Datenaufnahme als auch bei der Datennutzung) und die Informationen, die ihr zur Verfügung gestellt habt, waren von unschätzbarem Wert!
Andrija_Bgd
6

Versuchen Sie, sp_spaceusedauf Ihrer Datenbank zu laufen . Als Beispiel wird Folgendes zurückgegeben:

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

Um es in der Datenbank auszuführen, wird nur USEdie Datenbank ausgeführt sp_spaceused.

Wenn immer noch viel ungenutzter Speicherplatz angezeigt wird, können Sie den Schrumpf erneut versuchen. Manchmal finde ich, dass es mehrere Versuche dauert. Manchmal finde ich es auch am besten, die einzelne Datei und nicht die gesamte Datenbank zu verkleinern. Was Sie jedoch möglicherweise feststellen, ist, dass Sie über 2,9 TB Daten und weitere 4 + TB Indizes verfügen. In diesem Fall sind 7,5 TB ziemlich vernünftig. Wenn Sie ein Gefühl für den Speicherplatz (Daten und Index) jeder Tabelle bekommen möchten, können Sie diese auch sp_spaceusedauf Tabellenebene ausführen . Sie können es mit dem folgenden Befehl für alle Tabellen in der Datenbank ausführen:

EXEC sp_msforeachtable 'EXEC sp_spaceused [?];'

Obwohl die faire Warnung sp_msforeachtable nicht dokumentiert ist, nicht unterstützt wird und bekanntermaßen Tabellen fehlen. Andererseits hatte ich selbst ziemlich viel Glück damit.

Abgesehen davon sollte Ihre Datenbank abhängig von Ihrem erwarteten Wachstum einen bestimmten Prozentsatz an freiem Speicherplatz haben. Grundsätzlich möchten Sie sicherstellen, dass Sie Platz für 6 Monate bis zu ein paar Jahren Wachstum haben. Außerdem sollten Sie Ihre autogrowthEinstellungen überprüfen , um sicherzustellen, dass sie Ihrer Situation entsprechen. Insbesondere angesichts der Größe Ihrer Datenbank möchten Sie KEIN% verwenden autogrowth.

Kenneth Fisher
quelle
Vielen Dank! Ich habe sp_spaceused verwendet und es sieht so aus, als würden die tatsächlichen Daten tatsächlich den angegebenen Speicherplatz einnehmen, so seltsam das für mich angesichts der tatsächlichen Größe der geladenen Flatfiles klingen mag ... Indizes sind klein (ich habe ' Ich habe keine zusätzlichen erstellt, da sie in meinem Fall eher hinderlich als hilfreich gewesen wären. Ich denke, es sind nur die tatsächlichen Tische, die groß sind ... Vielen Dank für Ihre Hilfe!
Andrija_Bgd
Datenbanken belegen mehr Speicherplatz als Flatfiles. Aufgrund der Seitenstruktur entsteht ein gewisser Overhead für die Zeilen- und Tabellenstrukturen und ein gewisser Abfall.
Kenneth Fisher
-1

Verwenden Sie in SQL Management Studio 1.Rechtsklicken Sie auf die Datenbank und dann 2.Klicken Sie auf Aufgaben-> Verkleinern -> Dateien

Sie sehen einen Dialog, der Folgendes anzeigt: a. Derzeit zugewiesener Speicherplatz b. Verfügbarer freier Speicherplatz + (% frei)

Wenn Ihr% Free über 50% liegt, können Sie die Datei verkleinern. Ich habe diesen Treffer zu 90% gesehen. Wenn ich mich entscheide, die Datei zu verkleinern, setze ich sie normalerweise auf 2 oder 3 Gigs mehr als den aktuell zugewiesenen Speicherplatz. Die meisten meiner Datenbanken haben weniger als 50 GB. Wenn Sie also eine viel größere Datei haben, können Sie diese 10 Gigs groß machen. Ich mache mir normalerweise nur Sorgen um das Verkleinern, wenn ich die Datenbank auf einen anderen Server verschieben möchte. Sie können alles über das Verkleinern von Problemen auf jeder SQL-Seite lesen.

Clark Vera
quelle