PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Calculer et économiser de l'espace dans PostgreSQL

"Colonne Tetris"

En fait, vous pouvez faire quelque chose , mais cela nécessite une compréhension plus approfondie. Le mot-clé est remplissage d'alignement . Chaque type de données a des exigences d'alignement spécifiques.

Vous pouvez minimiser l'espace perdu pour le rembourrage entre les colonnes en les ordonnant favorablement. L'exemple (extrême) suivant gaspillerait beaucoup d'espace disque physique :

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)

Pour enregistrer 24 octets par ligne, utilisez à la place :

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<>jouez ici
Vieux sqlfiddle

En règle générale, si vous placez les colonnes de 8 octets en premier, puis les colonnes de 4 octets, 2 octets et 1 octet en dernier, vous ne pouvez pas vous tromper.

boolean , uuid (!) et quelques autres types n'ont pas besoin de rembourrage d'alignement. text , varchar et autres types "varlena" (longueur variable) nominalement nécessitent un alignement "int" (4 octets sur la plupart des machines). Mais je n'ai observé aucun rembourrage d'alignement au format disque (contrairement à la RAM). Finalement, j'ai trouvé l'explication dans une note dans le code source :

Notez également que nous autorisons la violation de l'alignement nominal lors du stockage de varlenas "compactées" ; le mécanisme TOAST s'occupe de le cacher à la plupart des codes.

Ainsi, l'alignement "int" n'est appliqué que lorsque la donnée (éventuellement compressée) comprenant un seul octet de longueur de tête dépasse 127 octets. Ensuite, le stockage varlena passe à quatre octets de tête et nécessite un alignement "int".

Normalement, vous pouvez au mieux économiser quelques octets par ligne en jouant à "column tetris" . Rien de tout cela n'est nécessaire dans la plupart des cas. Mais avec des milliards de lignes, cela peut signifier facilement quelques gigaoctets.

Vous pouvez tester la taille réelle des colonnes/lignes avec la fonction pg_column_size() .
Certains types occupent plus d'espace en RAM que sur disque (format compressé ou "packé"). Vous pouvez obtenir des résultats plus importants pour les constantes (format RAM) que pour les colonnes de table lorsque vous testez la même valeur (ou ligne de valeurs par rapport à la ligne de table) avec pg_column_size() .

Enfin, certains types peuvent être compressés ou "toastés" (stockés hors ligne) ou les deux.

Overhead par tuple (ligne)

4 octets par ligne pour l'identifiant de l'élément - non soumis aux considérations ci-dessus.
Et au moins 24 octets (23 + rembourrage) pour l'en-tête de tuple. Le manuel sur la mise en page de la base de données :

Il y a un en-tête de taille fixe (occupant 23 octets sur la plupart des machines), suivi d'un bitmap nul facultatif, d'un champ d'ID d'objet facultatif et des données utilisateur.

Pour le rembourrage entre l'en-tête et les données utilisateur, vous devez connaître MAXALIGN sur votre serveur - généralement 8 octets sur un système d'exploitation 64 bits (ou 4 octets sur un système d'exploitation 32 bits). Si vous n'êtes pas sûr, consultez pg_controldata .

Exécutez ce qui suit dans votre répertoire binaire Postgres pour obtenir une réponse définitive :

./pg_controldata /path/to/my/dbcluster

Le manuel :

Les données utilisateur réelles (colonnes de la ligne) commencent au décalage indiqué par t_hoff , qui doit toujours être un multiple de MAXALIGN distance pour la plate-forme.

Ainsi, vous obtenez généralement le stockage optimal en compressant les données en multiples de 8 octets.

Il n'y a rien à gagner dans l'exemple que vous avez posté . C'est déjà bien emballé. 2 octets de remplissage après le dernier int2 , 4 octets à la fin. Vous pourriez consolider le rembourrage à 6 octets à la fin, ce qui ne changerait rien.

Frais généraux par page de données

La taille de la page de données est généralement de 8 Ko. Quelques surcharges / ballonnements à ce niveau également :les restes ne sont pas assez grands pour contenir un autre tuple, et plus important encore, des lignes mortes ou un pourcentage réservé avec le FILLFACTOR réglage.

Il y a quelques autres facteurs à prendre en compte pour la taille sur le disque :

  • Combien d'enregistrements puis-je stocker dans 5 Mo de PostgreSQL sur Heroku ?
  • L'utilisation de NULL dans PostgreSQL n'utilise-t-elle pas toujours un bitmap NULL dans l'en-tête ?
  • Configurer PostgreSQL pour les performances de lecture

Types de tableaux ?

Avec un tableau tapez comme si vous évaluiez, vous ajouteriez 24 octets de surcharge pour le genre. De plus, les éléments du tableau occupent l'espace comme d'habitude. Rien à y gagner.