sql >> Database >  >> RDS >> PostgreSQL

Ruimte berekenen en besparen in PostgreSQL

"Kolom Tetris"

Eigenlijk kun je iets . doen , maar dit vereist een dieper begrip. Het sleutelwoord is uitlijning opvulling . Elk gegevenstype heeft specifieke uitlijningsvereisten.

U kunt ruimte die verloren gaat aan opvulling tussen kolommen minimize minimaliseren door ze gunstig te bestellen. Het volgende (extreme) voorbeeld zou veel fysieke schijfruimte verspillen:

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)

24 bytes opslaan per rij, gebruik in plaats daarvan:

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<>viool hier
Oude sqlfiddle

Als vuistregel kun je niet fout gaan als je eerst kolommen van 8 bytes en daarna kolommen van 4 bytes, 2 bytes en 1 byte als laatste plaatst.

boolean , uuid (!) en een paar andere typen hebben geen uitlijningspadding nodig. text , varchar en andere typen "varlena" (variabele lengte) nominaal vereisen "int" uitlijning (4 bytes op de meeste machines). Maar ik heb geen uitlijningspadding waargenomen in schijfindeling (in tegenstelling tot RAM). Uiteindelijk vond ik de uitleg in een notitie in de broncode:

Merk ook op dat we toestaan ​​dat de nominale uitlijning wordt geschonden bij het opslaan van "verpakte" varlenas; het TOAST-mechanisme zorgt ervoor dat dat voor de meeste code wordt verborgen.

Dus "int" uitlijning wordt alleen afgedwongen wanneer de (mogelijk gecomprimeerde) datum inclusief een enkele leidende lengte-byte groter is dan 127 bytes. Dan schakelt varlena-opslag over naar vier voorloopbytes en vereist uitlijning "int".

Normaal gesproken kunt u op zijn best een paar bytes per rij besparen door "column tetris" te spelen . Dit is in de meeste gevallen niet nodig. Maar met miljarden rijen kan dat al snel een paar gigabytes betekenen.

U kunt de werkelijke kolom- / rijgrootte testen met de functie pg_column_size() .
Sommige typen nemen meer ruimte in beslag in RAM dan op schijf (gecomprimeerd of "verpakt" formaat). U kunt grotere resultaten krijgen voor constanten (RAM-formaat) dan voor tabelkolommen wanneer u dezelfde waarde (of rij met waarden versus tabelrij) test met pg_column_size() .

Ten slotte kunnen sommige typen worden gecomprimeerd of "geroosterd" (buiten de rij opgeslagen) of beide.

Overhead per tupel (rij)

4 bytes per rij voor de item-ID - niet onderhevig aan bovenstaande overwegingen.
En ten minste 24 bytes (23 + opvulling) voor de tuple-header. De handleiding over de lay-out van de databasepagina:

Er is een header met een vaste grootte (die op de meeste machines 23 bytes in beslag neemt), gevolgd door een optionele null-bitmap, een optioneel veld voor object-ID en de gebruikersgegevens.

Voor de opvulling tussen koptekst en gebruikersgegevens moet u MAXALIGN . kennen op uw server - meestal 8 bytes op een 64-bits besturingssysteem (of 4 bytes op een 32-bits besturingssysteem). Als je het niet zeker weet, bekijk dan pg_controldata .

Voer het volgende uit in uw Postgres binaire map om een ​​definitief antwoord te krijgen:

./pg_controldata /path/to/my/dbcluster

De handleiding:

De daadwerkelijke gebruikersgegevens (kolommen van de rij) beginnen bij de offset die wordt aangegeven door t_hoff , wat altijd een veelvoud moet zijn van de MAXALIGN afstand voor het platform.

U krijgt dus meestal de optimale opslag door gegevens in veelvouden van 8 bytes te verpakken.

Er is niets te winnen in het voorbeeld dat je hebt gepost . Het zit al stevig ingepakt. 2 bytes opvulling na de laatste int2 , 4 bytes aan het einde. Je zou de opvulling aan het einde kunnen consolideren tot 6 bytes, wat niets zou veranderen.

Overhead per gegevenspagina

De grootte van de gegevenspagina is doorgaans 8 KB. Ook wat overhead / bloat op dit niveau:resten die niet groot genoeg zijn om in een andere tuple te passen, en nog belangrijker, dode rijen of een percentage gereserveerd met de FILLFACTOR instelling.

Er zijn nog een aantal andere factoren voor de grootte op de schijf waarmee u rekening moet houden:

  • Hoeveel records kan ik opslaan in 5 MB PostgreSQL op Heroku?
  • Gebruikt het gebruik van NULL in PostgreSQL nog steeds een NULL-bitmap in de koptekst?
  • PostgreSQL configureren voor leesprestaties

Arraytypen?

Met een array typt zoals u aan het evalueren was, zou u 24 bytes overhead . toevoegen voor de soort. Bovendien nemen array-elementen zoals gewoonlijk ruimte in beslag. Daar valt niets te winnen.



  1. Wat is het voordeel van het gebruik van SET XACT_ABORT ON in een opgeslagen procedure?

  2. FORMAT() Voorbeelden in MySQL

  3. SQL-alias uitgelegd

  4. Rijen dupliceren op basis van een kolomwaarde in elke rij