"Colonna Tetris"
In realtà, puoi fare qualcosa , ma questo richiede una comprensione più profonda. La parola chiave è imbottitura di allineamento . Ogni tipo di dati ha requisiti di allineamento specifici.
Puoi ridurre al minimo lo spazio perso per riempire tra le colonne ordinandoli favorevolmente. Il seguente (estremo) esempio sprecherebbe molto spazio su disco fisico:
CREATE TABLE t (
e int2 -- 6 bytes of padding after int2
, a int8
, f int2 -- 6 bytes of padding after int2
, b int8
, g int2 -- 6 bytes of padding after int2
, c int8
, h int2 -- 6 bytes of padding after int2
, d int8)
Per salvare 24 byte per riga, usa invece:
CREATE TABLE t (
a int8
, b int8
, c int8
, d int8
, e int2
, f int2
, g int2
, h int2) -- 4 int2 occupy 8 byte (MAXALIGN), no padding at the end
db<>gioca qui
Sqlfiddle vecchio
Come regola generale, se metti prima le colonne da 8 byte, poi le colonne da 4 byte, 2 byte e 1 byte per ultime, non puoi sbagliare.
boolean
, uuid
(!) e pochi altri tipi non necessitano di riempimento di allineamento. text
, varchar
e altri tipi "varlena" (lunghezza variabile) nominale richiedono l'allineamento "int" (4 byte sulla maggior parte delle macchine). Ma non ho osservato alcun riempimento di allineamento nel formato del disco (a differenza della RAM). Alla fine, ho trovato la spiegazione in una nota nel codice sorgente:
Si noti inoltre che consentiamo la violazione dell'allineamento nominale durante la memorizzazione di varlena "impacchettate"; il meccanismo TOAST si occupa di nasconderlo dalla maggior parte del codice.
Quindi l'allineamento "int" viene applicato solo quando il dato (possibilmente compresso) che include un singolo byte di lunghezza iniziale supera i 127 byte. Quindi lo storage varlena passa a quattro byte iniziali e richiede l'allineamento "int".
Normalmente, puoi risparmiare un paio di byte per riga nella migliore delle ipotesi giocando a "column tetris" . Niente di tutto ciò è necessario nella maggior parte dei casi. Ma con miliardi di righe può significare facilmente un paio di gigabyte.
Puoi testare la dimensione effettiva di colonna/riga con la funzione pg_column_size()
.
Alcuni tipi occupano più spazio nella RAM che su disco (formato compresso o "compresso"). Puoi ottenere risultati maggiori per le costanti (formato RAM) rispetto alle colonne della tabella quando esegui il test dello stesso valore (o riga di valori rispetto alla riga della tabella) con pg_column_size()
.
Infine, alcuni tipi possono essere compressi o "tostati" (memorizzati fuori linea) o entrambi.
Spese generali per tupla (riga)
4 byte per riga per l'identificatore dell'elemento, non soggetto alle considerazioni precedenti.
E almeno 24 byte (23 + riempimento) per l'intestazione della tupla. Il manuale sul layout di pagina del database:
C'è un'intestazione di dimensione fissa (che occupa 23 byte sulla maggior parte delle macchine), seguita da una bitmap nulla opzionale, un campo ID oggetto opzionale e i dati utente.
Per il riempimento tra intestazione e dati utente, è necessario conoscere MAXALIGN
sul tuo server - in genere 8 byte su un sistema operativo a 64 bit (o 4 byte su un sistema operativo a 32 bit). Se non sei sicuro, controlla pg_controldata
.
Esegui quanto segue nella tua directory binaria Postgres per avere una risposta definitiva:
./pg_controldata /path/to/my/dbcluster
Il manuale:
I dati utente effettivi (colonne della riga) iniziano all'offsetindicato da t_hoff
, che deve essere sempre un multiplo di MAXALIGN
distanza per la piattaforma.
Quindi in genere ottieni lo spazio di archiviazione ottimale comprimendo i dati in multipli di 8 byte.
Non c'è nulla da guadagnare nell'esempio che hai pubblicato . È già ben imballato. 2 byte di riempimento dopo l'ultimo int2
, 4 byte alla fine. Potresti consolidare il riempimento a 6 byte alla fine, il che non cambierebbe nulla.
Spese generali per pagina di dati
La dimensione della pagina dati è in genere di 8 KB. Qualche sovraccarico / rigonfiamento anche a questo livello:i resti non sono abbastanza grandi da contenere un'altra tupla e, soprattutto, righe morte o una percentuale riservata con il FILLFACTOR
impostazione.
Ci sono un paio di altri fattori da tenere in considerazione per la dimensione del disco:
- Quanti record posso archiviare in 5 MB di PostgreSQL su Heroku?
- Non si usa NULL in PostgreSQL, utilizza ancora una bitmap NULL nell'intestazione?
- Configurazione di PostgreSQL per le prestazioni di lettura
Tipi di array?
Con un array digita come se stessi valutando, aggiungeresti 24 byte di sovraccarico per il tipo. Inoltre, gli elementi dell'array occupano spazio come al solito. Non c'è niente da guadagnare.