Cette formation est sous licence CC-BY-NC-SA.
Vous êtes libre de la redistribuer et/ou modifier aux conditions
suivantes :
Paternité
Pas d’utilisation commerciale (y compris IA)
Partage des conditions initiales à l’identique
Marques déposées
PostgreSQL® Postgres® et le logo Slonik sont des marques
déposées par PostgreSQL Community Association of Canada.
Versions de
PostgreSQL couvertes
Ce document ne couvre que les versions supportées de PostgreSQL au
moment de sa rédaction, soit les versions 14 à 18.
Mécanique du moteur transactionnel & MVCC
Introduction
PostgreSQL utilise un modèle appelé MVCC
(Multi-Version Concurrency Control).
Gestion concurrente des transactions
Excellente concurrence
Impacts sur l’architecture
Au menu
Présentation de MVCC
Niveaux d’isolation
Implémentation de MVCC de PostgreSQL
Les verrous
Le mécanisme TOAST
Présentation de MVCC
Définitions
MultiVersion Concurrency Control
Contrôle de Concurrence Multi-Version
Plusieurs versions du même enregistrement
Granularité : l’enregistrement (pas le champ !)
Alternative à
MVCC : un seul enregistrement en base
Verrouillage en lecture et exclusif en écriture
Nombre de verrous ?
Contention ?
Cohérence ?
Annulation ?
Implémentation de MVCC par
undo
MVCC par undo :
une version de l’enregistrement dans la table
sauvegarde des anciennes versions
l’adresse physique d’un enregistrement ne change pas
la lecture cohérente est complexe
l’undo est complexe à dimensionner… et parfois
insuffisant
l’annulation est lente
Exemple : Oracle
L’implémentation MVCC de
PostgreSQL
Copy On Write (duplication à l’écriture)
Une version d’enregistrement n’est jamais modifiée
Toute modification entraîne une nouvelle version
Pas d’undo : pas de contention, ROLLBACK
instantané
Niveaux d’isolation
Principe des niveaux
d’isolation
Chaque transaction (et donc session) est isolée à un certain point :
elle ne voit pas les opérations des autres
elle s’exécute indépendamment des autres
Le niveau d’isolation au démarrage d’une transaction peut être
spécifié :
BEGIN ISOLATION LEVEL xxx;
Niveau READ UNCOMMITTED
Non disponible sous PostgreSQL
si demandé, s’exécute en READ COMMITTED
Lecture de données modifiées par d’autres transactions
non validées
Aussi appelé dirty reads
Dangereux
Pas de blocage entre les sessions
Niveau READ COMMITTED
Niveau d’isolation par défaut
La transaction ne lit que les données validées en base
Un ordre SQL s’exécute dans un instantané (les tables semblent
figées sur la durée de l’ordre)
L’ordre suivant s’exécute dans un instantané différent
Niveau REPEATABLE READ
Instantané au début de la transaction
Ne voit donc plus les modifications des autres transactions
Voit toujours ses propres modifications
Peut entrer en conflit avec d’autres transactions si modification
des mêmes enregistrements
Niveau SERIALIZABLE
Niveau d’isolation le plus élevé
Chaque transaction se croit seule sur la base
sinon annulation d’une transaction en cours
Avantages :
pas de « lectures fantômes »
évite des verrous, simplifie le développement
Inconvénients :
pouvoir rejouer les transactions annulées
toutes les transactions impliquées doivent être sérialisables
Blocs & lignes
Structure d’un bloc
1 bloc = 8 ko
ctid = (bloc, item dans le bloc)
Répartition des lignes au sein d’un bloc
(schéma de la documentation officielle, licence PostgreSQL)
xmin & xmax
Table initiale :
xmin
xmax
Nom
Solde
100
M. Durand
1500
100
Mme Martin
2200
xmin & xmax (suite)
BEGIN;UPDATE soldes SET solde = solde -200WHERE nom ='M. Durand';
xmin
xmax
Nom
Solde
100
150
M. Durand
1500
100
Mme Martin
2200
150
M. Durand
1300
xmin & xmax (suite)
UPDATE soldes SET solde = solde +200WHERE nom ='Mme Martin';
xmin
xmax
Nom
Solde
100
150
M. Durand
1500
100
150
Mme Martin
2200
150
M. Durand
1300
150
Mme Martin
2400
xmin & xmax (suite)
xmin
xmax
Nom
Solde
100
150
M. Durand
1500
100
150
Mme Martin
2200
150
M. Durand
1300
150
Mme Martin
2400
Comment est effectuée la suppression d’un enregistrement ?
Comment est effectuée l’annulation de la transaction 150 ?
CLOG
Le CLOG (Commit Log) enregistre l’état des
transactions.
Chaque transaction occupe 2 bits de CLOG (4 statuts)
COMMIT ou ROLLBACK très rapide
Référence pour savoir si une ligne est visible ou pas
Puis reporté dans les lignes (hint bits)
Avantages &
inconvénients du MVCC de PostgreSQL
Avantages du MVCC de
PostgreSQL
Avantages classiques de MVCC (concurrence d’accès)
Implémentation simple et performante
Peu de sources de contention
Verrouillage simple d’enregistrement
ROLLBACK instantané
Données conservées aussi longtemps que nécessaire
Inconvénients du MVCC de
PostgreSQL
Nettoyage des enregistrements
VACUUM
automatisation : autovacuum
Tables plus volumineuses
Écritures amplifiées
Pas de visibilité des lignes dans les index
Les colonnes supprimées impliquent reconstruction
Le wraparound
Le wraparound (1)
Wraparound : bouclage du compteur de
xmin/xmax
32 bits ~ 4 milliards
Le wraparound (2)
Après 4 milliards de transactions :
Le wraparound (3)
Concrètement ?
VACUUM FREEZE
géré par l’autovacuum
au pire, d’office
potentiellement beaucoup d’écritures
Optimisations de MVCC
HOT
Free Space Map
Visibility Map
Mise à jour jour HOT
HOT = Heap-Only Tuples
Si place dans le bloc
Si aucune colonne indexée modifiée
Alors la mise à jour se fait dans le même bloc
gain en mise à jour des index
gain en écritures et en utilisation du cache
Favorisée par un fillfactor < 100
Free Space Map
Fichier pointant les espaces libres des blocs
Optimisation des insertions
Visibility Map
Quels blocs sont intégralement visibles ?
Mise à jour par VACUUM
Utilisation :
Accélérer VACUUM et VACUUM FREEZE
Index Only Scan
Verrous
Verrouillage et MVCC
La gestion des verrous est liée à l’implémentation de MVCC
Verrouillage d’objets en mémoire
Verrouillage d’objets sur disque
Paramètres
Le gestionnaire de verrous
PostgreSQL possède un gestionnaire de verrous
Verrous d’objet
Niveaux de verrouillage
Empilement des verrous
Deadlock
Vue pg_locks
Verrous sur enregistrement
Le gestionnaire de verrous possèdes des verrous sur enregistrements
transitoires
le temps de poser le xmax
Utilisation de verrous sur disque
pas de risque de pénurie
Les verrous entre transaction se font sur leurs ID
La vue pg_locks
pg_locks :
visualisation des verrous en place
tous types de verrous sur objets
Complexe à interpréter :
verrous sur enregistrements pas directement visibles
Verrous - Paramètres
Nombre :
max_locks_per_transaction (+ paramètres pour la
sérialisation)
Durée :
lock_timeout (éviter l’empilement des verrous)
deadlock_timeout (défaut 1 s)
Trace :
log_lock_waits (1s)
log_lock_failures (’SELECT …FOR UPDATE NOWAIT`)
Pour tracer les échecs d’obtention de verrous par un
SELECT … FOR UPDATE NOWAIT, il faut configurer à
on le paramètre log_lock_failures (à partir de
PostgreSQL 18).
Durées de sessions,
transactions & ordres
Quelle durée pour
les sessions & transactions ?
Divers seuils possibles, jamais globalement.
SET …_timeout TO'5s' ;ALTERROLE … INDATABASE … SET..._timeout TO'…s'
Paramètre
Cible du seuil
lock_timeout
Attente de verrou
statement_timeout
Ordre en cours
idle_session_timeout
Session inactive
idle_in_transaction_session_timeout
Transaction en cours, inactive
transaction_timeout
(v17)
Transaction en cours
Quelle durée pour une session
?
Courte
coût & temps des connexions
pooler ?
Longue
risque de saturation du nombre de connexions
(rare) gaspillage mémoire par les backends
Quelle durée pour une
transaction ?
Courte
synchronisation fréquente coûteuse
Longue
verrous bloquants
TOAST
Mécanisme TOAST
TOAST : The Oversized-Attribute Storage Technique
Que faire si une ligne dépasse d’un bloc ?
Compresser
Déporter dans une table
Ou les deux
Inutile de le faire dans l’applicatif
Politique par champ
PLAIN/MAIN/EXTERNAL/EXTENDED
TOAST & table de
débordement
Table de débordement pg_toast_XXX
masquée, transparente
Jusqu’à 1 Go par champ (déconseillé)
texte, JSON, binaire…
compression optionnelle
Une raison de plus d’éviter les SELECT *
TOAST & compression
pglz (zlib) : défaut
lz4 : à préférer
généralement plus rapide
compression équivalente (à vérifier)
Mise en place :
default_toast_compression = lz4
ou :
ALTERTABLE t1 ALTERCOLUMN c2 SET COMPRESSION lz4 ;
Conclusion
PostgreSQL dispose d’une implémentation MVCC complète, permettant :
que les lecteurs ne bloquent pas les écrivains
que les écrivains ne bloquent pas les lecteurs
que les verrous en mémoire soient d’un nombre limité
Cela impose par contre une mécanique un peu complexe, dont les
parties visibles sont la commande VACUUM et le processus
d’arrière-plan autovacuum.