Cette section fournit un aperçu de TOAST (
The Oversized-Attribute Storage
Technique
, la technique de stockage des attributs trop
grands).
Puisque PostgreSQL™ utilise
une taille de page fixe (habituellement 8 Ko) et n'autorise pas
qu'une ligne s'étende sur plusieurs pages. Du coup, il n'est pas
possible de stocker de grandes valeurs directement dans les champs.
Pour dépasser cette limitation, les valeurs de champ volumineuses
sont compressées et/ou divisées en plusieurs lignes physiques. Ceci
survient de façon transparente pour l'utilisateur, avec seulement un
petit impact sur le code du serveur. Cette technique est connu sous
l'acronyme affectueux de TOAST (ou
« the best thing since sliced
bread »).
Seuls certains types de données supportent TOAST -- il n'est pas nécessaire d'imposer cette
surcharge sur les types de données qui ne produisent pas de gros
volumes. Pour supporter TOAST, un
type de données doit avoir une représentation (varlena) à longueur variable, dans laquelle les 32
premiers bits contiennent la longueur totale de la valeur en octets
(ceci incluant la longueur elle-même). TOAST n'a aucune contrainte supplémentaire sur la
représentation. Toutes les fonctions niveau C qui gèrent un type
données supportant TOAST doivent
faire attention à gérer les valeurs en entrée TOASTées. (Ceci se fait normalement en appelant
PG_DETOAST_DATUM avant de faire quoi que ce
soit avec une valeur en entrée; mais dans certains cas, des approches
plus efficaces sont possibles.)
TOAST empiète les deux bits de
poids fort sur le mot contenant la longueur varlena, limitant par
conséquent la taille logique de toute valeur d'un type de données
TOAST-able à 1 Go (230
- 1 octets). Quand les deux bits sont à zéro, cette valeur est une
valeur ordinaire, non TOASTée, du
type de données. Un des bits initialisé indique que la valeur a été
compressée et doit être décompressée avant d'être utilisée. L'autre
bit indique que la valeur a été stocké en dehors de la ligne. Dans ce
cas, le reste de la valeur est en réalité simplement un pointeur et
la véritable donnée se trouve ailleurs. Quand les deux bits sont
initialisés, les données sont stockées ailleurs tout en étant
compressées. Dans tous les cas, la longueur dans les bits de poids
faible du mot varlena indique la taille réelle de la donnée, pas la
taille de la valeur logique qui serait extraite par décompression ou
récupération de la donnée en dehors de la ligne.
Si une des colonnes d'une table est TOAST-able, la table disposera d'une table
TOAST associé, dont l'OID est
stockée dans l'entrée pg_class.
reltoastrelid
de la table. Les valeurs
TOASTées hors-ligne sont
conservées dans la table TOAST
comme décrit avec plus de détails ci-dessous.
La technique de compression utilisée est un simple et rapide membre
de la famille des techniques de compression LZ. Voir src/backend/utils/adt/pg_lzcompress.c pour les
détails.
Les valeurs hors-ligne sont divisées (après compression si
nécessaire) en morceaux d'au plus TOAST_MAX_CHUNK_SIZE octets (cette valeur est un peu
plus petite que BLCKSZ/4, soit à peu près
2000 octets par défaut). Chaque morceau est stocké comme une ligne
séparée dans la table TOAST de la
table propriétaire. Chaque table TOAST contient les colonnes
chunk_id
(un OID identifiant la valeur
TOASTée particulière),
chunk_seq
(un numéro de séquence pour le
morceau de la valeur) et
chunk_data
(la donnée réelle du morceau).
Un index unique sur
chunk_id
et
chunk_seq
offre une
récupération rapide des valeurs. Un pointeur datum représentant une
valeur TOASTée hors-ligne a par
conséquent besoin de stocker l'OID de la table TOAST dans laquelle chercher et l'OID de la
valeur spécifique (son
chunk_id
). Par commodité, les pointeurs
datums stockent aussi la taille logique du datum (taille de la donnée
originale non compressée) et la taille stockée réelle (différente si
la compression a été appliquée). A partir du mot d'en-tête varlena,
la taille totale d'un pointeur datum TOAST est par conséquent de 20 octets quelque
soit la taille réelle de la valeur représentée.
Le code TOAST est déclenché
seulement quand une valeur de ligne à stocker dans une table est plus
grande que BLCKSZ/4 octets (habituellement 2
Ko). Le code TOAST compressera
et/ou déplacera les valeurs de champ hors la ligne jusqu'à ce que la
valeur de la ligne soit plus petite que BLCKSZ/4 octets ou que plus aucun gain ne puisse être
réalisé. Lors d'une opération UPDATE, les valeurs des champs non
modifiées sont habituellement préservées telles quelles ; donc un
UPDATE sur une ligne avec des valeurs hors ligne n'induit pas de
coûts à cause de TOAST si aucune
des valeurs hors-ligne n'est modifiée.
Le code TOAST connaît quatre
stratégies différentes pour stocker les colonnes TOAST-ables :
-
PLAIN empêche soit la compression soit
le stockage hors-ligne. Ceci est la seule stratégie possible
pour les colonnes des types de données non TOAST-ables.
-
EXTENDED permet à la fois la
compression et le stockage hors-ligne. Ceci est la valeur par
défaut de la plupart des types de données TOAST-ables. La compression sera tentée en
premier, ensuite le stockage hors-ligne si la ligne est
toujours trop grande.
-
EXTERNAL autorise le stockage
hors-ligne mais pas la compression. L'utilisation d'EXTERNAL rendra plus rapides les opérations sur
des sous-chaînes d'importantes colonnes de type text et bytea (au
dépens d'un espace de stockage accrus) car ces opérations sont
optimisées pour récupérer seulement les parties requises de la
valeur hors-ligne lorsqu'elle n'est pas compressée.
-
MAIN autorise la compression mais pas
le stockage hors-ligne. (En réalité le stockage hors-ligne sera
toujours réalisé pour de telles colonnes mais seulement en
dernier ressort s'il n'existe aucune autre solution pour
diminuer suffisamment la taille de la ligne.)
Chaque type de données TOAST-able
spécifie une stratégie par défaut pour les colonnes de ce type de
donnée, mais la stratégie pour une colonne d'une table donnée peut
être modifiée avec
ALTER TABLE SET
STORAGE
.
Cette combinaison a de nombreux avantages comparés à une approche
plus directe comme autoriser le stockage des valeurs de lignes sur
plusieurs pages. En supposant que les requêtes sont habituellement
qualifiées par comparaison avec des valeurs de clé relativement
petites, la grosse partie du travail de l'exécuteur sera réalisée en
utilisant l'entrée principale de la ligne. Les grandes valeurs des
attributs TOASTés seront seulement
récupérées (si elles sont sélectionnées) au moment où l'ensemble de
résultats est envoyé au client. Ainsi, la table principale est bien
plus petite et un plus grand nombre de ses lignes tiennent dans le
cache du tampon partagé, ce qui ne serait pas le cas sans aucun
stockage hors-ligne. Le tri l'utilise aussi, et les tris seront plus
souvent réalisés entièrement en mémoire. Un petit test a montré
qu'une table contenant des pages HTML typiques ainsi que leurs URL
étaient stockées en à peu près la moitié de la taille des données
brutes en incluant la table TOAST
et que la table principale contenait moins de 10 % de la totalité des
données (les URL et quelques petites pages HTML). Il n'y avait pas de
différence à l'exécution en comparaison avec une table non
TOASTée, dans laquelle toutes les
pages HTLM avaient été coupées à 7 Ko pour tenir.