Haben Sie bei Ihren Größenschätzungen den Speicherplatz berücksichtigt, den Indizes belegen? Auch wenn Sie Textfelder haben, die als Multibyte ( N[VAR]CHAR
anstatt [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_spaceused
wird 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.objects
und sys.dm_db_partition_stats
in 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:
- Das, was nichts zugeordnet ist (dies zeigt in der ersten Ergebnismenge von
sp_spaceused
ohne angegebenes Objekt)
- Das, was einem Objekt zugeordnet ist (reserviert), aber derzeit nicht verwendet wird (dies zeigt sich in der "nicht verwendeten" Anzahl in
sp_spaceused
der Ausgabe.
- 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 ( TEXT
Spalten,[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.