Nelle stime delle dimensioni, hai preso in considerazione la quantità di spazio occupata dagli indici? Inoltre, se hai campi di testo impostati come multi-byte ( N[VAR]CHAR
anziché [VAR]CHAR
) e i file di input sono UTF-8 o semplici byte per carattere, ciò aumenterà i requisiti di archiviazione fino a un fattore due. Inoltre, ricorda che se hai una chiave / indice cluster su una tabella, la dimensione di questo influisce su tutti gli altri indici sulla tabella perché includono il valore della chiave cluster per ogni riga (quindi per dare un esempio estremo se una tabella ha un NCHAR (10 ) dove farebbe un INT e che è la tua chiave / indice cluster, non solo stai utilizzando altri 16 byte per riga nelle pagine di dati, ma sprechi anche 16 byte per riga in ogni altro indice di quella tabella ) .
Inoltre, alcuni spazi verranno allocati ma non utilizzati, sia perché il motore DB ha lasciato uno spazio allocato dopo le eliminazioni in modo che possa essere riutilizzato rapidamente per i nuovi dati in quella tabella o perché il modello di inserimenti ed eliminazioni ha lasciato solo molte pagine pieno.
Puoi eseguire:
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
per dare una rapida occhiata a quali tabelle occupano spazio.
Anche EXEC sp_spaceused
eseguito all'interno di quel DB restituirà due set di risultati. Il primo elenca lo spazio totale allocato nel filesystem per i file di dati e quanto non allocato, il secondo elenca la quantità di spazio allocato utilizzata per pagine di dati, pagine di indice o attualmente non utilizzata.
sp_spaceused
restituirà anche lo spazio utilizzato da un determinato oggetto, quindi è possibile eseguire questo ciclo per creare una tabella per l'analisi:
-- 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
Il codice sopra genererà tutte le dimensioni della tabella in un elenco, più una singola riga per i totali. Se necessario, è possibile utilizzare le varie viste di sistema (come sys.objects
e sys.dm_db_partition_stats
utilizzate nella prima query sopra, vedere http://technet.microsoft.com/en-us/library/ms177862.aspx per ulteriori dettagli) per ottenere maggiori dettagli come lo spazio utilizzato da ciascun indice.
Esistono tre classi di spazio inutilizzato in un file di dati:
- Ciò che non è assegnato a nulla (questo viene mostrato nel primo gruppo di risultati
sp_spaceused
senza alcun oggetto specificato)
- Ciò che è allocato a un oggetto (riservato) ma non attualmente utilizzato (questo viene mostrato nel conteggio "non utilizzato"
sp_spaceused
nell'output.
- Quello bloccato nelle pagine parzialmente utilizzate (questo sembrerà essere usato come tutto è allocato in blocchi di singole pagine, una pagina lunga 8.192 byte). Questo è più difficile da rilevare / calcolare. È dovuto a un mix di due fattori:
- Pagine divise. Man mano che i dati vengono aggiunti, si finisce spesso con pagine vuote in parte (il motore di archiviazione potrebbe sempre normalizzare il contenuto della pagina, ma ciò sarebbe molto inefficiente), e poiché le righe vengono eliminate i contenuti della pagina non vengono impacchettati automaticamente (di nuovo potrebbero essere, ma il extra Il carico di I / O è generalmente tutt'altro che utile).
- Il motore di archiviazione non dividerà una riga su più pagine (questo insieme alla dimensione della pagina da cui proviene il limite di 8.192 byte per riga). Se le tue righe hanno dimensioni fisse e occupano 1.100 byte ciascuna, "sprecherai" almeno 492 byte di ciascun blocco di dati assegnato a quella tabella (7 righe occupano 7.700 byte e un ottavo non si adatterà, quindi i restanti byte vinceranno ' essere usato). Più ampie sono le file, peggio può essere. Tabelle / indici con righe a lunghezza variabile (che sono molto più comuni di quelle a lunghezza completamente fissa) in genere sono migliori (ma sono meno facili da calcolare).
Un altro avvertimento qui sono oggetti di grandi dimensioni ( TEXT
colonne,[N]VARCHAR(MAX)
valori superiori a una determinata dimensione e così via) man mano che vengono posizionati fuori pagina, prendendo solo 8 byte nei dati della riga principale per contenere un puntatore ai dati altrove) in modo da poter interrompere il limite di 8.192 byte per riga.
tl; dr: stimare le dimensioni previste del database può essere molto più complicato di quanto non sia naturale supporre inizialmente.