"Spalten-Tetris"
Eigentlich kannst du etwas tun , aber dies erfordert ein tieferes Verständnis. Das Schlüsselwort ist Alignment Padding . Jeder Datentyp hat spezifische Ausrichtungsanforderungen.
Sie können den Platzverlust durch Auffüllen zwischen Spalten minimieren indem Sie sie günstig bestellen. Das folgende (extreme) Beispiel würde viel physischen Speicherplatz verschwenden:
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)
Um 24 Byte einzusparen pro Zeile verwenden Sie stattdessen:
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<>hier fummeln
Altes sqlfiddle
Als Faustregel gilt:Wenn Sie 8-Byte-Spalten zuerst und dann 4-Byte-, 2-Byte- und 1-Byte-Spalten zuletzt platzieren, können Sie nichts falsch machen.
boolean
, uuid
(!) und einige andere Typen benötigen keine Ausrichtungspolsterung. text
, varchar
und andere "varlena"-Typen (variable Länge) nominal erfordern eine "int"-Ausrichtung (4 Bytes auf den meisten Maschinen). Aber ich habe kein Alignment-Padding im Disk-Format beobachtet (anders als im RAM). Schließlich fand ich die Erklärung in einer Notiz im Quellcode:
Beachten Sie auch, dass wir zulassen, dass die nominelle Ausrichtung verletzt wird, wenn „gepackte“ Varlenas gelagert werden; der TOAST-Mechanismus sorgt dafür, dass dies vor dem meisten Code verborgen wird.
Daher wird die "int"-Ausrichtung nur erzwungen, wenn das (möglicherweise komprimierte) Datum einschließlich eines einzelnen führenden Längenbytes 127 Bytes überschreitet. Dann schaltet varlena storage auf vier führende Bytes um und erfordert ein "int"-Alignment.
Normalerweise können Sie ein paar Bytes pro Zeile sparen, wenn Sie "Column Tetris" spielen . Nichts davon ist in den meisten Fällen notwendig. Aber bei Milliarden von Zeilen kann es leicht ein paar Gigabyte bedeuten.
Die tatsächliche Spalten-/Zeilengröße können Sie mit der Funktion pg_column_size()
testen .
Einige Typen belegen mehr Platz im RAM als auf der Festplatte (komprimiertes oder "gepacktes" Format). Sie können größere Ergebnisse für Konstanten (RAM-Format) als für Tabellenspalten erhalten, wenn Sie denselben Wert (oder Zeile von Werten vs. Tabellenzeile) mit pg_column_size()
testen .
Schließlich können einige Typen komprimiert oder "geröstet" (out of line gespeichert) oder beides werden.
Overhead pro Tupel (Zeile)
4 Bytes pro Zeile für die Elementkennung - unterliegen nicht den obigen Überlegungen.
Und mindestens 24 Bytes (23 + Padding) für den Tupel-Header. Das Handbuch zum Datenbank-Seitenlayout:
Es gibt einen Header fester Größe (der auf den meisten Rechnern 23 Byte belegt), gefolgt von einer optionalen Null-Bitmap, einem optionalen Objekt-ID-Feld und den Benutzerdaten.
Für das Padding zwischen Kopf- und Nutzdaten müssen Sie MAXALIGN
kennen auf Ihrem Server - normalerweise 8 Bytes auf einem 64-Bit-Betriebssystem (oder 4 Bytes auf einem 32-Bit-Betriebssystem). Wenn Sie sich nicht sicher sind, sehen Sie sich pg_controldata
an .
Führen Sie Folgendes in Ihrem Postgres-Binärverzeichnis aus um eine definitive Antwort zu bekommen:
./pg_controldata /path/to/my/dbcluster
Das Handbuch:
Die eigentlichen Nutzdaten (Spalten der Zeile) beginnen bei dem durch t_hoff
angegebenen Offset , die immer ein Vielfaches von MAXALIGN
sein muss Entfernung zum Bahnsteig.
Sie erhalten also normalerweise das Speicheroptimum, indem Sie Daten in Vielfache von 8 Byte packen.
An dem von Ihnen geposteten Beispiel ist nichts zu gewinnen . Es ist schon dicht gepackt. 2 Bytes Auffüllen nach dem letzten int2
, 4 Bytes am Ende. Sie könnten das Padding am Ende auf 6 Bytes konsolidieren, was nichts ändern würde.
Overhead pro Datenseite
Die Datenseitengröße beträgt normalerweise 8 KB. Etwas Overhead / Aufblasen auch auf dieser Ebene:Reste, die nicht groß genug sind, um in ein anderes Tupel zu passen, und, was noch wichtiger ist, tote Zeilen oder ein Prozentsatz, der mit dem FILLFACTOR
reserviert ist Einstellung.
Es gibt ein paar andere Faktoren, die für die Größe auf der Festplatte berücksichtigt werden müssen:
- Wie viele Datensätze kann ich in 5 MB PostgreSQL auf Heroku speichern?
- Verwendet die Nichtverwendung von NULL in PostgreSQL immer noch eine NULL-Bitmap im Header?
- Konfigurieren von PostgreSQL für die Leseleistung
Array-Typen?
Mit einem Array eingeben, als würden Sie evaluieren, würden Sie 24 Byte Overhead hinzufügen für den Typ. Außerdem nehmen Array-Elemente wie üblich Platz ein. Da gibt es nichts zu gewinnen.