Les bases de données de PostgreSQL nécessitent
   des opérations de maintenance périodiques, connues sous le nom de
   VACUUM. Pour de nombreuses installations, il est
   suffisant de laisser travailler le démon
   autovacuum, qui est décrit dans Section 24.1.6.
   En fonction des cas, les paramètres de cet outil peuvent être optimisés
   pour obtenir de meilleurs résultats. Certains administrateurs de bases de
   données voudront suppléer ou remplacer les activités du démon avec une
   gestion manuelle des commandes VACUUM, qui seront
   typiquement exécutées suivant un planning par des scripts
   cron ou par le Task
   Scheduler. Pour configurer une gestion manuelle et correcte
   du VACUUM, il est essentiel de bien comprendre les quelques sous-sections
   suivantes. Les administrateurs qui se basent sur l'autovacuum peuvent
   toujours lire ces sections pour les aider à comprendre et à ajuster
   l'autovacuum.
  
    La commande VACUUM de
    PostgreSQL doit traiter chaque table
    régulièrement pour plusieurs raisons :
    
    Chacune de ces raisons impose de réaliser des opérations
    VACUUM de différentes fréquences et portées, comme
    expliqué dans les sous-sections suivantes.
   
    Il existe deux variantes de la commande VACUUM :
    le VACUUM standard et le VACUUM
    FULL. VACUUM FULL peut récupérer davantage
    d'espace disque mais s'exécute beaucoup plus lentement. Par ailleurs, la
    forme standard de VACUUM peut s'exécuter en parallèle
    avec les opérations de production des bases. Des commandes comme
    SELECT, INSERT,
    UPDATE et DELETE continuent de
    fonctionner de façon normale, mais la définition d'une table ne peut être
    modifiée avec des commandes telles que ALTER TABLE
    pendant le VACUUM. VACUUM FULL
    nécessite un verrou de type ACCESS EXCLUSIVE sur la
    table sur laquelle il travaille, et ne peut donc pas être exécuté en
    parallèle avec une autre activité sur la table. Par conséquent, en règle
    générale, les administrateurs doivent s'efforcer d'utiliser la commande
    standard VACUUM et éviter VACUUM
    FULL.
   
    VACUUM génère un nombre important d'entrées/sorties, ce
    qui peut entraîner de mauvaises performances pour les autres sessions
    actives. Des paramètres de configuration peuvent être ajustés pour
    réduire l'impact d'un nettoyage en arrière plan sur les
    performances  --  voir Section 19.4.4.
   
    Avec PostgreSQL, les versions périmées des
    lignes ne sont pas immédiatement supprimées après une commande
    UPDATE ou DELETE. Cette approche
    est nécessaire pour la cohérence des accès concurrents
    (MVCC, voir le Chapitre 13) : la
    version de la ligne ne doit pas être supprimée tant qu'elle est
    susceptible d'être lue par une autre transaction. Mais en fin de compte,
    une ligne qui est plus vieille que toutes les transactions en cours n'est
    plus utile du tout. La place qu'elle utilise doit être rendue pour être
    réutilisée par d'autres lignes afin d'éviter un accroissement constant,
    sans limite, du volume occupé sur le disque. Cela se fait en exécutant
    un VACUUM.
   
    La forme standard de VACUUM élimine les versions
    d'enregistrements morts dans les tables et les index, et marque l'espace
    comme réutilisable. Néanmoins, il ne rend pas cet espace au système
    d'exploitation, sauf dans le cas spécial où des pages à la fin d'une
    table deviennent totalement vides et qu'un verrou exclusif sur la table
    peut être obtenu aisément. Par opposition, VACUUM FULL
    compacte activement les tables en écrivant une nouvelle version complète
    du fichier de la table, sans espace vide. Ceci réduit la taille de la
    table mais peut prendre beaucoup de temps. Cela requiert aussi un espace
    disque supplémentaire pour la nouvelle copie de la table jusqu'à la fin
    de l'opération.
   
    Le but habituel d'un nettoyage régulier est de lancer des
    VACUUM standard suffisamment souvent pour éviter
    d'avoir recours à un VACUUM FULL. Le démon autovacuum
    essaie de fonctionner de cette façon, et n'exécute jamais de
    VACUUM FULL. Avec cette approche, l'idée directrice
    n'est pas de maintenir les tables à leur taille minimale, mais de
    maintenir l'utilisation de l'espace disque à un niveau constant :
    chaque table occupe l'espace équivalent à sa taille minimale plus la
    quantité d'espace consommée entre deux nettoyages. Bien que
    VACUUM FULL puisse être utilisé pour qu'une table
    retrouve sa taille minimale et rendre l'espace disque au système
    d'exploitation, cela ne sert pas à grand chose, si cette table recommence
    à grossir rapidement après. Par conséquent, cette approche s'appuyant sur
    des commandes VACUUM exécutées à intervalles
    modérément rapprochés est une meilleure approche que d'exécuter des
    VACUUM FULL espacés pour des tables mises à jour de
    façon intensive.
   
    Certains administrateurs préfèrent planifier le passage de
    VACUUM eux-mêmes, par exemple faire le travail de
    nuit, quand la charge est faible. La difficulté avec cette stratégie est
    que si une table a un pic d'activité de mise à jour inattendu, elle peut
    grossir au point qu'un VACUUM FULL soit vraiment
    nécessaire pour récupérer l'espace. L'utilisation du démon d'autovacuum
    minore ce problème, puisque le démon planifie les nettoyages de façon
    dynamique, en réponse à l'activité de mise à jour. Il est peu raisonnable
    de désactiver totalement le démon, sauf si l'activité de la base est
    extrêmement prévisible. Un compromis possible est de régler les
    paramètres du démon afin qu'il ne réagisse qu'à une activité
    exceptionnellement lourde de mise à jour, de sorte à seulement éviter de
    perdre totalement le contrôle de la volumétrie, tout en laissant les
    VACUUM planifiés faire le gros du travail quand la
    charge est normale.
   
    Pour ceux qui n'utilisent pas autovacuum, une approche typique alternative
    est de planifier un VACUUM sur la base complète une
    fois par jour lorsque l'utilisation n'est pas forte, avec en plus des
    opérations de VACUUM plus fréquentes pour les tables
    très impactées par des mises à jour, de la façon adéquate.
    (Certaines installations avec énormément de mises à jour peuvent exécuter
    des nettoyages toutes les quelques minutes.) Lorsqu'il y a plusieurs
    bases dans une instance, il faut penser à exécuter un
    VACUUM sur chacune d'elles ; le programme vacuumdb peut se révéler utile dans ce contexte.
   
     Le VACUUM standard peut ne pas suffire quand une table
     contient un grand nombre d'enregistrements morts comme conséquence d'une
     mise à jour ou d'une suppression massive. Dans ce cas, s'il est
     nécessaire de récupérer l'espace disque gaspillé, plusieurs commandes
     sont utilisables : VACUUM FULL, CLUSTER ou une des
     variantes de ALTER
     TABLE. Ces commandes écrivent une nouvelle copie de la
     table et reconstruisent ses index. Toutes ces options nécessitent un
     verrou de type ACCESS EXCLUSIVE. Elles utilisent
     aussi temporairement un espace disque supplémentaire, approximativement
     égal à la taille de la table, car les anciennes copies de la table et
     des index ne peuvent pas être supprimées avant la fin de l'opération.
    
     Si le contenu d'une table est supprimé périodiquement, il est préférable
     d'envisager l'utilisation de TRUNCATE, plutôt que
     DELETE suivi de VACUUM.
     TRUNCATE supprime le contenu entier de la table
     immédiatement sans nécessiter de VACUUM ou
     VACUUM FULL pour réclamer l'espace disque maintenant
     inutilisé. L'inconvénient est la violation des sémantiques MVCC
     strictes.
    
    L'optimiseur de requêtes de PostgreSQL s'appuie
    sur des informations statistiques produites à partir du contenu des
    tables dans l'optique de produire des plans d'exécutions efficaces pour
    les requêtes. Ces statistiques sont collectées par la commande ANALYZE , qui peut être
    invoquée seule ou comme option de VACUUM. Il est
    important d'avoir des statistiques relativement à jour, ce qui permet
    d'éviter les choix de mauvais plans d'exécution, pénalisant les
    performances de la base.
   
    Si activé, le démon autovacuum va automatiquement exécuter des commandes
    ANALYZE à chaque fois que le contenu d'une table aura
    changé suffisamment. Toutefois, un administrateur peut préférer se fier à
    des opérations ANALYZE planifiées manuellement, en
    particulier s'il est connu que l'activité de mise à jour de la table n'a
    pas d'impact sur les statistiques des colonnes
    « intéressantes ». Le démon planifie des
    ANALYZE en fonction du nombre d'enregistrements
    insérés, mis à jour ou supprimés ; il n'a aucune connaissance du
    fait que cela générera ou pas des modifications intéressantes au niveau
    des statistiques.
   
    Les lignes modifiées dans les partitions et les enfants, dans le cadre de
    l'héritage, ne déclenchent pas d'analyse sur la table parent. Si la table
    parent est vide ou rarement modifiée, elle pourrait ne jamais être traitée
    par l'autovacuum, et les statistiques pour l'arbre d'héritage en entier ne
    seront pas récupérées. Il est nécessaire d'exécuter
    ANALYZE manuellement sur la table parent pour
    conserver des statistiques à jour.
   
    À l'instar du nettoyage pour récupérer l'espace, les statistiques doivent
    être plus souvent collectées pour les tables intensément modifiées que
    pour celles qui le sont moins. Mais même si la table est très modifiée,
    il se peut que ces collectes soient inutiles si la distribution
    probabiliste des données évolue peu. Une règle simple pour décider est de
    voir comment évoluent les valeurs minimale et maximale des données. Par
    exemple, une colonne de type timestamp qui contient la date
    de mise à jour de la ligne aura une valeur maximale en continuelle
    croissance au fur et à mesure des modifications ; une telle colonne
    nécessitera plus de collectes statistiques qu'une colonne qui contient
    par exemple les URL des pages accédées sur un site web. La colonne qui
    contient les URL peut très bien être aussi souvent modifiée mais la
    distribution probabiliste des données changera certainement moins
    rapidement.
   
    Il est possible d'exécuter ANALYZE sur des tables
    spécifiques, voire des colonnes spécifiques ; il y a donc une grande
    flexibilité pour mettre à jour certaines statistiques plus souvent que
    les autres en fonction des besoins de l'application. Quoi qu'il en soit,
    dans la pratique, il est généralement mieux de simplement analyser la
    base entière car il s'agit d'une opération rapide.
    ANALYZE utilise un système d'échantillonnage des lignes
    d'une table, ce qui lui évite de lire chaque ligne.
   
     Même si il n'est pas très productif de règler précisément la fréquence de
     ANALYZE pour chaque colonne, il peut être intéressant
     d'ajuster le niveau de détail des statistiques collectées pour chaque
     colonne. Les colonnes très utilisées dans les clauses
     WHERE et dont la distribution n'est pas uniforme
     requièrent des histogrammes plus précis que les autres colonnes. Voir
     ALTER TABLE SET STATISTICS, ou modifier les
     paramètres par défaut de la base de données en utilisant le paramètre de
     configuration default_statistics_target.
    
De plus, par défaut, il existe peu d'informations sur la sélectivité des fonctions. Néanmoins, si vous créez un objet statistique ou un index sur une fonction, des statistiques utiles seront récupérées sur la fonction, ce qui peut grandement améliorer les plans de requêtes qui utilisent l'index.
     Le démon autovacuum ne lance pas de commandes ANALYZE
     sur les tables distantes car il n'a aucun moyen de déterminer la
     fréquence à laquelle la mise à jour des statistiques serait utile. Si
     vos requêtes ont besoin des statistiques sur les tables distantes pour
     disposer d'un plan d'exécution correct, une bonne idée serait de lancer
     manuellement des commandes ANALYZE sur ces tables au
     moment adéquat.
    
     Le démon autovacuum n'exécute pas de commandes ANALYZE
     pour les tables partitionnées. Les parents seront seulement analysées si le
     parent lui-même est modifié. Les changements dans les tables enfants ne
     déclenchent pas d'analyse automatique sur la table parent. Si vos requêtes
     nécessitent des statistiques sur les tables parents pour être correctement
     planifiées, il sera nécessaire d'exécuter périodiquement un
     ANALYZE manuels sur ces tables pour garder des
     statistiques à jour.
    
La commande VACUUM maintient le contenu de la carte de visibilité de chaque table, pour conserver la trace de chaque bloc contenant seulement des lignes connues pour être visibles par toutes les transactions actives (ainsi que les futures transactions, jusqu'à la prochaine modification de la page). Cette carte a deux buts. Tout d'abord, le nettoyage peut ignorer ce type de blocs à la prochaine exécution du VACUUM comme il n'y a rien à nettoyer dans ces blocs.
Ensuite, il permet à PostgreSQL de répondre à certaines requêtes en utilisant seulement l'index, et donc sans faire référence à la table sous-jacente. Comme les index dans PostgreSQL ne contiennent pas d'informations sur la visibilité des lignes, un parcours d'index normal récupère la ligne de la table pour chaque entrée d'index correspondante, ce qui permet de vérifier si la ligne correspondante est bien visible par la transaction en cours. Un parcours d'index seuls vérifie en premier lieu la carte de visibilité. S'il est connu que toutes les lignes du bloc sont visibles, la lecture de la table peut être évitée. Ceci est très utile sur les gros ensembles de données où la carte de visibilité peut éviter des accès disques. La carte de visibilité est bien plus petite que la table, donc elle peut facilement être mise en cache même quand la table est très grosse.
Le mécanisme de contrôle de concurrence multiversion (MVCC) de PostgreSQL s'appuie sur la possibilité de comparer des identifiants de transactions (XID) : la version d'une ligne dont le XID d'insertion est supérieur au XID de la transaction en cours est « dans le futur » et ne doit pas être visible de la transaction courante. Comme les identifiants ont une taille limitée (32 bits), une instance qui est en activité depuis longtemps (plus de 4 milliards de transactions) pourrait connaître un cycle complet des identifiants de transaction : le XID reviendra à 0 et soudainement les transactions du passé sembleront appartenir au futur - ce qui signifie qu'elles deviennent invisibles. En bref, perte de données totale. (En réalité, les données sont toujours là mais c'est un piètre réconfort puisqu'elles restent inaccessibles.) Pour éviter ceci, il est nécessaire d'exécuter un VACUUM sur chaque table de chaque base au moins une fois tous les deux milliards de transactions.
    La raison pour laquelle un nettoyage régulier résout le problème est qu'un
    VACUUM marquera les lignes comme
    gelées, indiquant qu'elles ont été insérées par une
    transaction suffisamment ancienne pour que les effets de cette
    transaction soient visibles à coup sûr par toutes les transactions
    actuelles et futures. Les XID normaux sont comparés sur une base
    modulo-232. Cela signifie que pour chaque XID
    normal, il y en a deux milliards qui sont plus vieux et deux milliards
    qui sont plus récents. Une autre manière de le dire est que l'ensemble de
    définition des XID est circulaire et sans limite. De ce fait, pour une
    ligne créée avec un XID normal donné, cette version de la ligne apparaît
    comme appartenant au passé pour les deux milliards de transactions qui
    suivront quelque soit le XID de ces transactions. Si cette version de
    ligne existe toujours après deux milliards de transactions, elle
    apparaîtra soudainement comme appartenant au futur. Pour empêcher cela,
    PostgreSQL réserve un XID spécial, appelé
    FrozenTransactionId, qui ne suit pas les règles
    normales de comparaison de XID et qui est toujours considéré comme plus
    ancien que chaque XID normal. Les versions de lignes gelées sont traitées
    comme si la XID d'insertion était FrozenTransactionId,
    pour qu'elles apparaissent dans le passé pour les autres transactions
    normales, quelque soit les soucis de cycle d'identifiants de
    transactions, et donc ces versions de lignes seront valides jusqu'à leur
    suppression, quelque soit la durée que cela représente.
   
     Dans les versions de PostgreSQL antérieures à
     la 9.4, le gel était implémenté en remplaçant le XID d'insertion d'une
     ligne avec FrozenTransactionId, qui était visible
     dans la colonne système xmin de la ligne. Les
     nouvelles versions ajoutent un drapeau, préservant le
     xmin original de la ligne pour une utilisation
     ultérieure (notamment pour du débugage). Néanmoins, il est toujours
     possible d'avoir des lignes pour lesquelles
     xmin vaut
     FrozenTransactionId (2) dans les bases de données
     antérieures à la version 9.4 traitées par
     pg_upgrade.
    
     De plus, les catalogues systèmes pourraient contenir des lignes avec
     xmin égale à
     BootstrapTransactionId (1), indiquant qu'elles ont
     été insérées lors de la première phase
     d'initdb. Comme
     FrozenTransactionId, cet XID spécial est traité comme
     étant plus ancien que tout autre XID normal.
    
vacuum_freeze_min_age contrôle l'âge que doit avoir une valeur XID avant que des lignes comportant ce XID ne soient gelées. Augmenter la valeur de ce paramètre peut permettre d'éviter un travail inutile si les lignes à geler vont bientôt être modifiées. Diminuer ce paramètre augmente le nombre de transactions qui peuvent survenir avant un nouveau nettoyage de la table.
    VACUUM utilise la carte de
    visibilité pour déterminer les blocs à parcourir sur une table.
    Habituellement, il ignore les blocs qui n'ont aucune ligne morte même si
    ces blocs pourraient toujours avoir des versions de lignes avec des
    identifiants très anciens de transactions. De ce fait, les
    VACUUM normaux ne vont pas toujours geler chaque
    ancienne version de ligne dans la table.
    Quand cela arrive, VACUUM aura besoin de réaliser un
    vacuum agressif, qui gèlera toutes les valeurs
    XID et MXID non gelées et éligibles, ceci incluant celles de pages
    dont les enregistrements d'un bloc sont tous visibles mais pas gelés.
    En pratique, la plupart des tables requiert un nettoyage agressif périodique.
    vacuum_freeze_table_age contrôle quand
    VACUUM se comporte ainsi : les blocs ne contenant
    que des lignes vivantes mais non gelées sont parcourus si le nombre de
    transactions exécutées depuis le dernier parcours de ce type est plus
    grand que vacuum_freeze_table_age moins
    vacuum_freeze_min_age. Configurer
    vacuum_freeze_table_age à 0 force
    VACUUM à toujours utiliser cette stratégie plus agressive.
   
    Le délai maximum où une table peut rester sans nettoyage est de deux
    millions de transactions moins vacuum_freeze_min_age
    lors du dernier VACUUM agressif. Si elle devait rester
    sans nettoyage après cela, des pertes de données pourraient survenir.
    Pour s'assurer que cela n'arrive pas, autovacuum est appelé sur chaque
    table qui pourrait contenir des lignes non gelées dont les XID ont un âge
    plus avancé que le paramètre de configuration autovacuum_freeze_max_age. (Ceci arrivera même si
    autovacuum est désactivé.)
   
    Ceci implique que, si aucune opération de VACUUM n'est demandée sur une
    table, l'autovacuum sera automatiquement déclenché une fois toutes les
    autovacuum_freeze_max_age moins
    vacuum_freeze_min_age transactions. Pour les tables
    qui bénéficient régulièrement de l'opération de VACUUM pour réclamer
    l'espace perdu, ceci a peu d'importance. Néanmoins, pour les tables
    statiques (en incluant les tables qui ont des insertions mais pas de
    mises à jour et de suppressions), il n'est pas nécessaire d'exécuter un
    VACUUM pour récupérer de la place et donc il peut être utile d'essayer de
    maximiser le délai entre les autovacuums forcés sur de très grosses
    tables statiques. Évidemment, vous pouvez le faire soit en augmentant
    autovacuum_freeze_max_age soit en diminuant
    vacuum_freeze_min_age.
   
    Le maximum efficace pour vacuum_freeze_table_age est
    0.95 * autovacuum_freeze_max_age ; un paramétrage
    plus haut que ça sera limité à ce maximum. Une valeur plus importante que
    autovacuum_freeze_max_age n'aurait pas de sens car un
    autovacuum de préservation contre le cycle des identifiants de
    transactions serait déclenché, et le multiplicateur 0,95 laisse un peu de
    place pour exécuter un VACUUM manuel avant que cela ne
    survienne. Comme règle d'or, vacuum_freeze_table_age
    devrait être configuré à une valeur légèrement inférieure à
    autovacuum_freeze_max_age, laissant suffisamment
    d'espace pour qu'un VACUUM planifié régulièrement ou
    pour qu'un autovacuum déclenché par des activités normales de suppression
    et de mise à jour puissent être activés pendant ce laps de temps. Le
    configurer de façon trop proche pourrait déclencher des autovacuum de
    protection contre la ré-utilisation des identifiants de transactions,
    même si la table a été récemment l'objet d'un VACUUM pour récupérer
    l'espace, alors que des valeurs basses amènent à des VACUUM agressifs
    plus fréquents.
   
    Le seul inconvénient à augmenter
    autovacuum_freeze_max_age
    (et vacuum_freeze_table_age avec elle) est que les
    sous- répertoires pg_xact et
    pg_commit_ts de l'instance prendront plus de place
    car ils doivent stocker le statut et l'horodatage
    (si track_commit_timestamp est activé) du COMMIT pour
    toutes les transactions depuis
    autovacuum_freeze_max_age. L'état de COMMIT utilise
    deux bits par transaction, donc si
    autovacuum_freeze_max_age et
    vacuum_freeze_table_age ont une valeur maximale
    permise de deux milliards, pg_xact peut grossir
    jusqu'à la moitié d'un Go et pg_commit_ts jusqu'à 20
    Go. Si c'est rien comparé à votre taille de base totale, configurer
    autovacuum_freeze_max_age à son maximum permis est
    recommandé. Sinon, le configurer suivant ce que vous voulez comme
    stockage maximum dans pg_xact et dans
    pg_commit_ts. (La valeur par défaut, 200 millions de
    transactions, se traduit en à peu près 50 Mo de stockage dans
    pg_xact et à peu près 2 Go de stockage pour
    pg_commit_ts.)
   
    Un inconvénient causé par la diminution de
    vacuum_freeze_min_age est que cela pourrait faire que
    VACUUM travaille sans raison : geler une version
    de ligne est une perte de temps si la ligne est modifiée rapidement
    après (ce qui fait qu'elle obtiendra un nouveau XID). Donc ce paramètre
    doit être suffisamment important pour que les lignes ne soient pas gelées
    jusqu'à ce qu'il soit pratiquement certain qu'elles ne seront plus
    modifiées.
   
    Pour tracer l'âge des plus anciens XID non gelés de la base,
    VACUUM stocke les statistiques sur XID dans les tables
    systèmes pg_class et
    pg_database. En particulier, la colonne
    relfrozenxid de la ligne
    pg_class d'une table contient le XID final du gel
    qui a été utilisé par le dernier VACUUM agressif pour
    cette table. Il est garanti que tous les XID plus anciens que ce XID ont été
    remplacés par FrozenXID pour cette table.  Toutes les
    lignes insérées par des transactions dont le XID est plus ancien que ce XID
    sont garanties d'avoir été gelées.  En particulier, la colonne
    relfrozenxid de la ligne de
    pg_class pour une table contient les XID non gelés
    les plus ancients restants à la fin du plus récent VACUUM
    qui a avancé avec succès relfrozenxid
    (typiquement le VACUUM agressif le plus récent).  De façon similaire, la
    colonne datfrozenxid de la ligne
    pg_database de la base est une limite inférieure
    des XID non gelés apparaissant dans cette base  --  c'est tout simplement
    le minimum des valeurs relfrozenxid par table
    dans cette base. Pour examiner cette information, le plus simple est
    d'exécuter des requêtes comme :
    
SELECT c.oid::regclass as table_name,
       greatest(age(c.relfrozenxid),age(t.relfrozenxid)) as age
FROM pg_class c
LEFT JOIN pg_class t ON c.reltoastrelid = t.oid
WHERE c.relkind IN ('r', 'm');
SELECT datname, age(datfrozenxid) FROM pg_database;
    La colonne age mesure le nombre de transactions à
    partir du XID final vers le XID de transaction en cours.
   
     Quand la clause VERBOSE de la commande
     VACUUM est utilisée, VACUUM affiche
     différentes statistiques sur la table. Ceci inclut des informations sur
     l'avancement de relfrozenxid et de
     relminmxid, et le nombre de blocs nouvellement
     gelés. Les mêmes détails apparaissent dans
     le journal applicatif du serveur si les actions de l'log_autovacuum_min_duration) sont tracées sur une opération
     VACUUM exécutée par autovacuum.
    
    Habituellement, VACUUM parcourt seulement les blocs qui
    ont été modifiés depuis le dernier nettoyage mais
    relfrozenxid peut seulement être avancé quand
    tous les blocs d'une table pouvant contenir des XID gelés sont parcourus.
    Ceci survient quand relfrozenxid a plus de
    vacuum_freeze_table_age transactions antérieures, quand
    l'option FREEZE de VACUUM est utilisée
    ou quand tous les blocs qui ne sont pas encore gelés nécessitent un
    nettoyage pour supprimer les versions de lignes mortes. Quand
    VACUUM parcourt chaque bloc d'une table qui n'est pas
    déjà entièrement gelé, il doit configurer age
    (relfrozenxid) à une valeur un peu au-dessus de la configuration
    utilisée pour vacuum_freeze_min_age (plus par le nombre
    de transactions démarrées depuis le lancement de VACUUM).
    VACUUM initialisera
    relfrozenxid au XID le plus ancien qui reste dans
    la table, donc il est possible que la valeur finale soit bien plus récente
    que strictement nécessaire.  Si aucun VACUUM avec
    avancement de relfrozenxid n'est lancé sur la
    table, une fois arrivé à autovacuum_freeze_max_age, un
    autovacuum est forcé sur la table.
   
Si, pour une certaine raison, l'autovacuum échoue à effacer les anciens XID d'une table, le système commencera à émettre des messages d'avertissement comme ceci quand les plus anciens XID de la base atteignent les 40 millions de transactions à partir du point de réinitialisation :
WARNING: database "mydb" must be vacuumed within 39985967 transactions HINT: To avoid XID assignment failures, execute a database-wide VACUUM in that database.
    (Une commande VACUUM manuelle devrait résoudre le
    problème, comme suggéré par le message HINT ; mais notez que la
    commande VACUUM doit être exécutée par un
    super-utilisateur, sinon elle échouera à mettre à jour les catalogues,
    ce qui l'empêchera d'avancer le champ
    datfrozenxid de la base.) Si ces avertissements
    sont ignorés, le système refusera d'assigner de nouveaux identifiants de
    transactions dès qu'il n'en restera que trois millions avant la
    réinitialisation :
    
ERROR:  database is not accepting commands that assign new XIDs to avoid wraparound data loss in database "mydb"
HINT:  Execute a database-wide VACUUM in that database.
    
    Dans ce cas, toute transaction en cours peut continuer, mais seules des
    transactions en lecture seule peuvent démarrées. Les opérations qui modifient
    les enregistrements de la base de données ou qui tronquent des relations
    échoueront. La commande VACUUM peut toujous être
    exécutée normalement. Notez que, contrairement à ce qui a pu être
    recommandé dans des versions précédentes, il n'est ni
    nécessaire ni souhaité d'arrêter le processus postmaster ou d'entrer en
    mode utilisateur-seul pour restaurer le fonctionnement normal. À la place,
    suivez ces étapes :
    
age(transactionid) est grand. De telles transactions
       doivent être validées ou annulées.age(backend_xid) ou
       age(backend_xmin) est grand. De telles transactions
       doivent être validées ou annulées. Si ce n'est pas possible, les sessions
       associées doivent être fermées en utilisant la fonction
       pg_terminate_backend.age(xmin) ou
       age(catalog_xmin) est grand. Dans de nombreux cas, ces
       slots ont été créées pour de la réplication vers un serveur qui n'existe
       plus ou qui est arrêté depuis longtemps. Si vous supprimez un slot pour
       un serveur qui existe toujours ou pourrait de nouveau se connecter à ce
       slot, cette réplication pourrait nécessiter d'être reconstruite.VACUUM dans la base cible. Un
       VACUUM sur la base complète est le plus simple ;
       pour réduire le temps nécessaire pour l'opération, il est aussi possible
       d'exécuter des commandes VACUUM manuelles sur les
       tables ayant le champ relminxid le plus
       ancien. N'utilisez pas VACUUM FULL dans ce cas car
       il nécessite un identifiant de transaction, ce qui fera échouer
       l'opération, sauf dans le mode super-utilisateur où il consommera un
       identifiant de transaction et augmentera de ce fait le risque d'une
       réutilisation des identifiants de transaction. N'utilisez pas non plus
       VACUUM FREEZE parce qu'il fera plus que la quantité
       minimal de travail requis pour restaurer le fonctionnement normal.
       
     Dans les version sprécédentes, il était parfois nécessaire d'arrêter le
     processus postlaster et de lancer la commande VACUUM en
     mode utilisateur-simple. Dans les scénarios habituels, ceci n'est plus
     nécessaire et doit être éviter autant que possible car cela implique
     d'arrêter le système. C'est aussi plus risqué car cela désactive les
     protections sur la réutilisation des identifiants de transaction, prévues
     pour éviter les pertes de données. La seule raison pour utiliser le mode
     utilisateur-simple est si vous souhaitez utiliser
     TRUNCATE ou DROP sur des tables
     inutiles pour éviter de lancer VACUUM sur celles-ci. La
     marge de sécurité de trois millions de transactions existe pour permettre à
     l'administrateur de le faire. Voir la page de référence postgres pour des détails sur l'utilisation du mode
     utilisateur-simple.
    
     Les identifiants multixact sont utilisés pour
     supporter le verrouillage de lignes par des transactions multiples.
     Comme l'espace est limité dans un en-tête de ligne pour y stocker des
     informations, cette information est codée sous la forme d'un
     « identifiant de transaction multiple », ou ID multixact pour
     faire court, à chaque fois qu'il y a plus d'une transaction cherchant à
     verrouiller en parallèle une ligne. Les informations sur les
     identifiants de transactions inclus dans tout identifiant multixact sont
     enregistrées séparément dans le sous-répertoire
     pg_multixact et seul l'identifiant multixact
     apparaît dans le champ xmax de l'en-tête de
     ligne. Comme les identifiants de transactions, les identifiants
     multi-transactions sont implémentés avec un compteur 32 bits et le
     stockage correspondant, ce qui nécessite une gestion attentive, un
     nettoyage du stockage et la gestion du cycle (plus exactement de la
     ré-utilisation des identifiants). Il existe un espace de stockage séparé
     qui détient la liste des membres dans chaque multixact, qui utilise
     aussi un compteur sur 32 bits et qui doit aussi être géré. La fonction
     système pg_get_multixact_members() décrite dans
     Tableau 9.82 peut être utilisé pour examiner
     les identifiants de transaction associés avec un identifiant MultiXact.
    
     Quand VACUUM parcourt une partie d'une table, il
     remplacera tout ID multixact qu'il rencontre, plus âgé que vacuum_multixact_freeze_min_age, par une valeur
     différente, qui peut être la valeur zéro, un identifiant de transaction
     ou un nouvel identifiant multixact. Pour chaque table,
     pg_class.relminmxid
     enregistre le plus ancien identifiant multixact possible apparaissant
     déjà dans un enregistrement de cette table. Si cette valeur est plus
     ancienne que vacuum_multixact_freeze_table_age, un
     vacuum agressif est forcé. Comme indiqué dans la section précédente, un
     vacuum agressif signifie que seuls les blocs connus pour être
     entièrement gelés sont ignorés. mxid_age() peut
     être utilisé sur
     pg_class.relminmxid
     pour trouver son âge.
    
     Des VACUUM agressifs, quel qu'en soit la cause, sont
     garantie de pouvoir avancer le
     relminmxid de la table.  Comme toutes les tables
     de toutes les bases sont parcourues et que leurs plus anciennes valeurs
     multixact sont avancées, le stockage sur disque pour les anciens multixacts
     peut être supprimé.
    
Comme moyen de sécurité supplémentaire, un VACUUM agressif surviendra pour toute table dont l'âge en identifiant multixact est supérieur à autovacuum_multixact_freeze_max_age. De plus, si le stockage occupé par les membres multixacts dépasse environ 10 Go, des parcours de vacuum agressif surviendront plus fréquemment pour toutes les tables, en commençant par celles qui ont le plus ancien multixact-age. Ces deux types de parcours agressifs de tables surviendront seulement si l'autovacuum est désactivé spécifiquement. L'aire de stockage des membres pourraient grossir jusqu'à environ 20 Go avant d'atteindre la limite de réutilisation des identifiants.
Similaire au cas de l'identifiant de transaction, si l'autovacuum échoue à effacer les anciens identifiants MultiXact d'une table, le système commencera à emetre des messages d'avertissement quand les plus anciens identifiants MultiXact de la base attendront les 40 millions de transactions du point de réutilisation. Et, tout comme dans le cas des identifiants de transactions, si ces messages sont ignorés, le système refusera de générer de nouveaux identifiants MultiXact une fois qu'il en restera moins de trois millions.
Quand les identifiants MultiXact sont épuisés, le retour à une situation normale s'obtient de la même façon que quand des identifiants de transactions sont épuisés. Suivez les mêmes étapes que dans la section précédente mais avec les différences suivantes :
pg_stat_activity ; néanmoins,
        rechercher les anciens identifiants de transactions est toujours une
        bonne facçon de déterminer les transactions pouvant poser des soucis de
        réutilisation des identifiants de MultiXact.
       
    PostgreSQL  dispose d'une fonctionnalité
    optionnelle mais hautement recommandée appelée
    autovacuum, dont le but est d'automatiser
    l'exécution des commandes VACUUM et
    ANALYZE. Quand il est activé, autovacuum vérifie les
    tables ayant un grand nombre de lignes insérées, mises à jour ou
    supprimées. Ces vérifications utilisent la fonctionnalité de récupération
    de statistiques ; du coup, autovacuum ne peut être utilisé que si
    track_counts est configuré à
    true. Dans la configuration par défaut, l'autovacuum
    est activé et les paramètres liés sont correctement configurés.
   
    Le « démon autovacuum » est constitué de plusieurs processus.
    Un processus démon permanent appelé autovacuum
    launcher(autrement dit le lanceur d'autovacuum) est en charge
    de lancer des processus de traitement
    (autovacuum worker) pour toutes les bases de
    données. Le lanceur distribue le travail dans le temps en lançant un
    nouveau processus de traitement sur chaque base de données chaque autovacuum_naptime secondes. (Du coup, si l'installation
    a N bases de données, un nouveau
    autovacuum worker sera lancé tous les
    autovacuum_naptime/N
    secondes.) Un maximum de autovacuum_max_workers
    processus autovacuum worker est autorisé à
    s'exécuter en même temps. S'il y a plus de
    autovacuum_max_workers bases à traiter, la prochaine
    base de données sera traitée dès qu'un autre processus de traitement a
    terminé. Chaque processus de traitement vérifie chaque table de la base
    de données de connexion et exécute un VACUUM et/ou un
    ANALYZE suivant les besoins. log_autovacuum_min_duration peut être utilisé pour
    superviser l'activité des processus autovacuum worker.
   
Si plusieurs grosses tables deviennent toutes éligibles à un VACUUM dans un court espace de temps, tous les processus de traitement pourraient avoir à exécuter des VACUUM sur ces tables pendant un long moment. Ceci pourraient avoir pour résultat que d'autres tables et d'autres bases de données ne puissent pas être traitées tant qu'un processus de traitement ne sera pas disponible. Il n'y a pas de limite sur le nombre de processus de traitement sur une seule base, mais ils essaient d'éviter de répéter le travail qui a déjà été fait par d'autres. Notez que le nombre de processus de traitement en cours d'exécution n'est pas décompté des limites max_connections et superuser_reserved_connections.
    Les tables dont la valeur de relfrozenxid est
    supérieure à autovacuum_freeze_max_age font
    toujours l'objet d'un VACUUM (cela s'applique aussi aux tables dont le freeze max age
    a été modifié avec les paramètres de stockage ; voir plus bas).
    Sinon, si le nombre de lignes obsolètes
    depuis le dernier VACUUM dépasse une « limite de
    vacuum », la table bénéficie d'un VACUUM. La limite est définie
    ainsi :
    
limite du vacuum = limite de base du vacuum + facteur d'échelle du vacuum * nombre de lignes
    où la limite de base du vacuum est
    autovacuum_vacuum_threshold,
    le facteur d'échelle du vacuum est
    autovacuum_vacuum_scale_factor
    et le nombre de lignes est
    pg_class.reltuples.
   
La table est aussi traitée si le nombre de lignes insérées depuis le dernier VACUUM a dépassé la limite d'insertion définie d'après cette formule :
limite insertion vacuum = limite insertion base vacuum + facteur échelle insertion vacuum * nombre de lignes
    
    où la limite d'insertion de base du VACUUM correspond au paramètre autovacuum_vacuum_insert_threshold, et le facteur
    d'échelle d'insertion du VACUUM correspond au paramètre autovacuum_vacuum_insert_scale_factor. De tels VACUUM
    permettent de marquer des portions de la table comme tout
    visible et permettent aussi de geler les lignes, ce qui peut
    réduire le travail requis par les VACUUM suivant. Pour les tables
    recevant des opérations INSERT mais aucune ou très peu
    d'opérations UPDATE/DELETE, il peut
    être bénéfique de diminuer la valeur du paramètre autovacuum_freeze_min_age pour la table car cela
    permet le gel des lignes par des VACUUM rapides. Le nombre de lignes
    obsolètes et le nombre de lignes insérées sont obtenus via le système
    de statistiques cumulatives ; c'est un nombre généralement
    cohérent mis à jour par
    chaque opération UPDATE, DELETE et
    INSERT. (C'est seulement moyennement précis car
    certaines informations pourraient être perdues en cas de fortes charges.)
    Si la valeur du champ relfrozenxid pour la
    table est supérieure à vacuum_freeze_table_age, un
    VACUUM agressif est réalisé pour geler les anciennes lignes et avancer la
    valeur de relfrozenxid, sinon seules les blocs
    qui ont été modifiés depuis le dernier VACUUM sont parcourues par
    l'opération de VACUUM.
   
Pour ANALYZE, une condition similaire est utilisée : la limite, définie comme
limite du analyze = limite de base du
    analyze + facteur d'échelle du analyze * nombre de
    lignes est comparée au nombre de lignes insérées, mises
    à jour et supprimées depuis le dernier ANALYZE.
   
    Les tables partitionnées ne contiennent pas de lignes et ne sont donc
    pas traitées par l'autovacuum. (L'autovacuum traite les partitions
    comme toute autre table.)) Malheureusement, ceci signifie
    que l'autovacuum n'exécute pas d'ANALYZE sur les tables
    partitionnées, et ceci peut occasionner des plans non optimaux pour les
    requêtes qui référencent les statistiques de la table partitionnée. Vous
    pouvez contourner ce problème en exécutant manuellement
    ANALYZE sur les tables partitionnées quand elles sont
    peuplées la première fois, et à chaque fois que la distribution des données
    changent dans les partitions.
   
Les tables temporaires ne peuvent pas être accédées par l'autovacuum. De ce fait, les opérations appropriées de VACUUM et d'ANALYZE devraient être traitées par des commandes SQL de session.
    Les limites et facteurs d'échelle par défaut sont pris dans
    postgresql.conf, mais il est possible de les
    surcharger table par table (ainsi que beaucoup d'autres paramètres de
    contrôle de l'autovacuum) ; voir Paramètres de stockage pour plus d'informations.
    Si une configuration a été modifiée via les paramètres de stockage d'une
    table, cette valeur est utilisée lors du traitement de cette table. Dans
    le cas contraire, les paramètres globaux sont utilisés. Voir Section 19.10 pour plus de détails sur les
    paramètres globaux.
   
    Quand plusieurs autovacuum workers travaillent, les paramètres de délai de
    coût de l'autovacuum (voir Section 19.4.4) sont
    « réparties » parmi tous les processus pour que l'impact total
    en entrée/sortie sur le système soit identique quelque soit le nombre de
    processus en cours d'exécution. Néanmoins, tout autovacuum worker
    traitant des tables et dont les paramètres de stockage
    autovacuum_vacuum_cost_delay ou
    autovacuum_vacuum_cost_limit ont été configurés
    spécifiquement ne sont pas considérés dans l'algorithme de répartition.
   
    Les processus de traitement de l'autovacuum ne bloquent généralement pas
    les autres commandes. Si un processus tente d'acquérir un verrou qui
    entre en conflit avec le verrou SHARE UPDATE EXCLUSIVE
    détenu par autovacuum, la demande de verrou interrompra l'autovacuum.
    Pour les modes de verrou entrant en conflit, voir Tableau 13.2. Néanmoins, si l'autovacuum
    s'exécute pour empêcher une réutilisation des identifiants de transaction
    (c'est-à-dire si le texte de la requête de l'autovacuum dans la vue
    pg_stat_activity se termine avec le texte
    (to prevent wraparound)), l'autovacuum n'est pas
    automatiquement interrompu.
   
     Exécuter régulièrement des commandes qui acquièrent des verrous en
     conflit avec un verrou SHARE UPDATE EXCLUSIVE
     (par exemple ANALYZE) peut gêner fortement le traitement réalisé par
     l'autovacuum.