Perché lo spazio dati di una tabella potrebbe occupare una dimensione 4x dei dati grezzi?


18

Ho una tabella con 490 M righe e 55 GB di spazio tabella, quindi circa 167 byte per riga. La tabella ha tre colonne: a VARCHAR(100), a DATETIME2(0)e a SMALLINT. La lunghezza media del testo nel VARCHARcampo è di circa 21,5, quindi i dati non elaborati dovrebbero essere di circa 32 byte per riga: 22 + 2 per il VARCHAR, 6 per il DATETIME2e 2 per il numero intero a 16 bit.

Si noti che lo spazio sopra è solo dati, non indici. Sto usando il valore riportato in Proprietà | Conservazione | Generale | Spazio dati.

Ovviamente ci deve essere un certo sovraccarico, ma 135 byte per riga sembrano molti, specialmente per una tabella di grandi dimensioni. Perché potrebbe essere? Qualcun altro ha visto moltiplicatori simili? Quali fattori possono influenzare la quantità di spazio aggiuntivo richiesto?

Per confronto, ho provato a creare una tabella con due INTcampi e 1 M righe. Lo spazio dati richiesto era 16,4 MB: 17 byte per riga, rispetto a 8 byte di dati non elaborati. Un'altra tabella di test con an INTe aVARCHAR(100) popolato con lo stesso testo della tabella reale utilizza 39 byte per riga (44 K righe), dove mi aspetterei 28 più un po '.

Quindi la tabella di produzione ha un considerevole sovraccarico. È perché è più grande? Mi aspetto che le dimensioni dell'indice siano all'incirca N * log (N), ma non vedo perché lo spazio richiesto per i dati effettivi sia non lineare.

Grazie in anticipo per eventuali suggerimenti!

MODIFICARE:

Tutti i campi elencati sono NOT NULL. La tabella reale ha un PK cluster sul VARCHARcampo e sul DATETIME2campo, in quell'ordine. Per i due test, il primo INTera il PK (raggruppato).

Se è importante: la tabella è una registrazione dei risultati del ping. I campi sono URL, data / ora del ping e latenza in millisecondi. I dati vengono costantemente aggiunti e mai aggiornati, ma i dati vengono eliminati periodicamente per ridurli a pochi record all'ora per URL.

MODIFICARE:

Una risposta molto interessante qui suggerisce che, per un indice con molta lettura e scrittura, la ricostruzione potrebbe non essere utile. Nel mio caso, lo spazio consumato è un problema, ma se le prestazioni di scrittura sono più importanti, si potrebbe essere meglio con indici flaccidi.

Risposte:


11

Dopo le discussioni nei commenti sulla domanda originale, in questo caso sembra che lo spazio perso sia causato dalla scelta della chiave raggruppata, che ha portato a una massiccia frammentazione.

Vale sempre la pena verificare lo stato di frammentazione tramite sys.dm_db_index_physical_stats in queste situazioni.

Modifica: dopo l'aggiornamento nei commenti

La densità di pagina media (prima della ricostruzione dell'indice cluster) era del 24%, che si adatta perfettamente alla domanda originale. Le pagine erano piene solo di 1/4, quindi la dimensione totale era 4x della dimensione dei dati grezzi.


7

Le strutture su disco hanno un sovraccarico:

  • intestazione di riga
  • bitmap + puntatore null
  • offset di colonne a lunghezza variabile
  • puntatori versione riga (opzionale)
  • ...

Prendendo 2 x 4 byte int colonne, hai

  • Intestazione di riga di 4 byte
  • Puntatore a 2 byte a NULL bitmap
  • 8 byte per 2 colonne int
  • Bitmap NULL a 3 byte

Wow 17 byte!

Puoi fare lo stesso per la tua seconda tabella di test che ha un sovraccarico maggiore di quello originale:

  • 2 byte per il conteggio delle colonne di lunghezza variabile
  • 2 byte per colonna a lunghezza variabile

Perché la differenza Inoltre (non collegherò a questi)

  • hai mai ricostruito gli indici per deframmentarli?
  • le eliminazioni non recuperano lo spazio
  • le pagine di dati verranno divise se inserite nel mezzo
  • gli aggiornamenti possono causare puntatori in avanti (lascia un vuoto)
  • overflow della riga
  • rimossa la colonna varchar senza ricostruzione dell'indice o DBCC CLEANTABLE
  • heap o tabella (heap non ha un indice cluster = record sparsi ovunque)
  • Livello di isolamento RCSI (extra 14 byte per riga)
  • spazi finali (SET ANSI_PADDING è ON per impostazione predefinita) in varchar. Usa DATALENGTH per pulire, non LEN
  • Esegui sp_spaceused con @updateusage = 'true'
  • ...

Vedi questo: SQL Server: come creare una tabella che riempie una pagina da 8 KB?

Da SO:


Il campione della colonna int da 2x4 byte non è corretto al 100%. Avrai un'intestazione di riga di 4 byte (2 byte di stato e 2 byte per la dimensione dei dati a lunghezza fissa). Quindi avrai 2x4 byte per i dati. Due byte per il conteggio delle colonne e un singolo byte per la bitmap null, fornendo una lunghezza totale del record di 15 byte, non 17.
Mark S. Rasmussen,

@Mark S. Rasmussen: Dove ottieni "2 byte per la dimensione dei dati a lunghezza fissa"? MSDN? E la bitmap nulla è sempre 3 byte: sqlskills.com/blogs/paul/post/... + msdn.microsoft.com/en-us/library/ms178085%28v=sql.90%29.aspx
gbn

Caspita, grande dettaglio! Ho considerato il campo di lunghezza della VARCHARs nella mia stima sopra, ma non per il conteggio delle colonne. Questa tabella non ha campi NULLable (avrebbe dovuto menzionarlo), alloca ancora byte per loro?
Jon of All Trades,

La ricostruzione degli indici influirebbe sulla parte dei dati dello spazio richiesto? Forse ricostruire l'indice cluster sarebbe. Gli inserti si verificano nel mezzo, molto, anche se se scambiassi l'ordine dei campi di cluster che si fermerebbe. La maggior parte del resto non dovrebbe applicarsi in questo caso, ma è un ottimo riferimento per il caso generale. Controllerò i tuoi link. Roba buona!
Jon of All Trades,

1
@gbn I 2 byte per la dimensione dei dati a lunghezza fissa fanno parte dell'intestazione della riga a 4 byte che hai citato. Questo è il puntatore che punta alla fine della porzione di lunghezza dei dati fissi / inizio del conteggio delle colonne / bitmap null. La bitmap NULL non è sempre di tre byte. Se includi il conteggio delle colonne, sarà un minimo di tre byte, ma potrebbe essere maggiore: ho diviso la bitmap e il conteggio delle colonne nella mia descrizione. Inoltre, la bitmap NULL non è sempre presente, sebbene lo sarà in questo caso.
Mark S. Rasmussen,

5

I tipi di dati sono cambiati nel tempo? Le colonne a lunghezza variabile sono state rimosse? Gli indici sono stati deframmentati spesso ma mai ricostruiti? Molte righe sono state eliminate o molte colonne di lunghezza variabile sono state aggiornate in modo significativo? Qualche buona discussione qui .


Sono sicuro al 97% di non aver modificato un tipo di dati o di aver rimosso un campo. Se l'avessi fatto, sarebbe stato molto presto quando la tabella avesse molte meno righe. Non ci sono cancellazioni o aggiornamenti, i dati vengono sempre e solo aggiunti.
Jon of All Trades,

Correzione: ci sono cancellazioni e abbastanza. La tabella ha una crescita netta considerevole, quindi immagino che questo spazio sarebbe rapidamente riutilizzato, però.
Jon of All Trades,

Con molte eliminazioni, i dati possono essere riutilizzati o meno. Qual è la chiave di clustering della tabella? Gli inserti sono al centro del tavolo o alla fine?
mrdenny,

La chiave cluster è composta, sui campi VARCHARe DATETIME2, in questo ordine. Gli inserti verranno distribuiti uniformemente per il primo campo. Per il secondo campo, nuovi valori e saranno sempre maggiori di quelli esistenti.
Jon of All Trades,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.