Le module pg_stat_statements fournit un moyen de
  surveiller les statistiques d'optimisation et d'exécution de tous les
  ordres SQL exécutés par un serveur.
 
  Le module doit être chargé par l'ajout de
  pg_stat_statements à shared_preload_libraries dans le fichier de configuration
  postgresql.conf parce qu'il a besoin de mémoire
  partagée supplémentaire. Ceci signifie qu'il faut redémarrer le serveur
  pour ajouter ou supprimer le module. De plus, le calcul de l'identifiant de
  requête doit être activé pour que le module soit actif, ce qui est fait
  automatiquement si compute_query_id est configuré à
  auto ou on, ou tout autre module
  tiers chargé qui calcule les identifiants de requête.
 
  Quand pg_stat_statements est actif, il récupère des
  statistiques sur toutes les bases de données du serveur. Pour y accéder et
  les manipuler, le module fournit les vues
  pg_stat_statements et
  pg_stat_statements_info, et les fonctions
  pg_stat_statements_reset et
  pg_stat_statements. Elles ne sont pas disponibles
  globalement mais peuvent être activées pour une base de données spécifique
  avec l'instruction CREATE EXTENSION pg_stat_statements.
 
pg_stat_statements
   Les statistiques collectées par le module sont rendues disponibles par une
   vue nommée pg_stat_statements. Cette vue contient
   une ligne pour chaque combinaison d'un identifiant de base de données,
   d'un identifiant utilisateur, d'un identifiant de requête et s'il s'agit
   d'une requête principale ou non (jusqu'au nombre maximum d'ordres
   distincts que le module peut surveiller). Les colonnes de la vue sont
   affichées dans Tableau F.20.
  
Tableau F.20. Colonnes de pg_stat_statements
Type de colonne Description  | 
|---|
         OID de l'utilisateur qui a exécuté la requête  | 
         OID de la base dans laquelle a été exécutée la requête  | 
        
       True si la requête a été exécutée comme instruction de haut niveau
       (toujours true si   | 
         Code de hachage, calculé à partir de l'arbre d'analyse de la requête  | 
         Texte d'une requête représentative  | 
         
        Nombre d'optimisations de la requête
        (si   | 
         
        Durée totale passée à optimiser la requête, en millisecondes
        (si   | 
         
        Durée minimale passée à optimiser la requête, en millisecondes
        (si   | 
         
        Durée maximale passée à optimiser la requête, en millisecondes
        (si   | 
         
        Durée moyenne passée à optimiser la requête, en millisecondes
        (si   | 
         
        Déviation standard de la durée passée à optimiser la requête, en
        millisecondes
        (si   | 
         Nombre d'exécutions de la requête  | 
         Durée totale passée à exécuter la requête, en millisecondes  | 
         Durée minimale passée à exécuter la requête, en millisecondes  | 
         Durée maximale passée à exécuter la requête, en millisecondes  | 
         Durée moyenne passée à exécuter la requête, en millisecondes  | 
         Déviation standard de la durée passée à exécuter la requête, en millisecondes  | 
         Nombre total de lignes récupérées ou affectées par la requête  | 
         Nombre total de blocs lus dans le cache partagé par la requête  | 
         Nombre total de blocs lus hors cache partagé par la requête  | 
         Nombre total de blocs modifiés dans le cache partagé par la requête  | 
         Nombre total de blocs du cache partagé écrit sur disque par la requête  | 
         Nombre total de blocs lus dans le cache local par la requête  | 
         Nombre total de blocs lus hors du cache local par la requête  | 
         Nombre total de blocs modifiés dans le cache local par la requête  | 
         Nombre total de blocs du cache local écrit sur disque par la requête  | 
         Nombre total de blocs lus dans les fichiers temporaires par la requête  | 
         Nombre total de blocs écrits dans les fichiers temporaires par la requête  | 
         Durée totale de lecture des blocs des fichiers de données (hors cache) par la requête, en millisecondes (si track_io_timing est activé, sinon zéro)  | 
         Durée totale de l'écriture des blocs des fichiers de données (hors cache) par la requête, en millisecondes (si track_io_timing est activé, sinon zéro)  | 
        Durée totale des lectures des blocs de fichiers temporaires en millisecondes (si track_io_timing est activé, sinon zéro)  | 
        Durée totale des écritures des blocs de fichiers temporaires en millisecondes (si track_io_timing est activé, sinon zéro)  | 
         Nombre total d'enregistrements générés dans les WAL par la requête  | 
         Nombre total d'images complètes de blocs (full page images) générés dans les WAL par la requête  | 
         Nombre total d'octets générés dans les WAL par la requête  | 
        Nombre total de fonctions compilées par JIT pour cette requête  | 
        Durée totale passée par la requête sur la génération de code JIT, en millisecondes  | 
        Nombre de fois où les fonctions ont été incluses  | 
        Durée totale passée par la requête sur l'inclusion de fonctions, en millisecondes  | 
        Nombre de fois où la requête a été optimisée  | 
        Durée totale passée sur l'optimisation de la requête, en millisecondes  | 
        Nombre de fois où du code a été émis  | 
        Durée totale passée par la requête sur de l'émission de code, en millisecondes  | 
   Pour raisons de sécurité, seuls les superutilisateurs et les rôles
   disposant des droits du
   rôle pg_read_all_stats sont autorisé à voir le texte
   SQL ainsi que le champ queryid des requêtes
   exécutées par d'autres utilisateurs.  Les autres utilisateurs peuvent
   cependant voir les statistiques, si la vue a été installée dans leur base
   de données.
  
   Les requêtes qui disposent d'un plan d'exécution
   (c'est-à-dire SELECT, INSERT,
   UPDATE, DELETE et
   MERGE) sont combinées en
   une entrée unique dans pg_stat_statements
   lorsqu'elles ont un plan d'exécution similaire (d'après leur hachage). En
   substance, cela signifie que deux requêtes seront considérées comme
   équivalentes si elles sont sémantiquement les mêmes mais disposent de
   valeurs littérales différentes dans la requête. Les requêtes utilitaires
   (c'est-à-dire toutes les autres) ne sont considérées comme unique que
   lorsqu'elles sont égales au caractère près.
  
    Les détails suivant sur le remplacement des constantes et le
    queryid s'appliquent seulement si compute_query_id est activé. Si vous utilisez un module
    externe pour calculer queryid, vous devez vous
    référer à sa documentation pour les détails.
   
   Quand la valeur d'une constante a été ignorée pour pouvoir comparer la
   requête à d'autres requêtes, la constante est remplacée par un symbole de
   paramètre, tel que $1, dans l'affichage de
   pg_stat_statements.  Le reste du texte de la
   requête est tel qu'était la première requête ayant la valeur de hashage
   queryid spécifique associée à l'entrée dans
   pg_stat_statements.
  
   Dans certains cas, les requêtes SQL avec des textes différents peuvent être
   fusionnés en une seule entrée pg_stat_statements.
   Normalement, cela n'arrive que pour les requêtes dont la sémantique est
   équivalente, mais il y a une petite chance que des collisions de
   l'algorithme de hachage aient pour conséquence la fusion de requêtes sans
   rapport en une entrée. (Cela ne peut cependant pas arriver pour des
   requêtes appartenant à des utilisateurs différents ou des bases de données
   différentes).
  
   Puisque la valeur de hachage queryid est
   calculée sur la représentation de la requête après analyse, l'inverse est
   également possible : des requêtes avec un texte identique peuvent
   apparaître comme des entrées séparées, si elles ont des significations
   différentes en fonction de facteurs externes, comme des réglages de
   search_path différents.
  
   Les programmes utilisant pg_stat_statements
   pourraient préférer utiliser queryid (peut-être
   en association avec dbid et
   userid) pour disposer d'un identifiant plus
   stable et plus sûr pour chaque entrée plutôt que le texte de la requête.
   Cependant, il est important de comprendre qu'il n'y a qu'une garantie
   limitée sur la stabilité de la valeur de hachage de
   queryid.  Puisque l'identifiant est dérivé de
   l'arbre après analyse, sa valeur est une fonction, entre autres choses, des
   identifiants d'objet interne apparaissant dans cette représentation.  Cela
   a des implications paradoxales.  Par exemple,
   pg_stat_statements considérera deux requêtes
   apparemment identiques comme distinctes, si elles référencent une table qui
   a été supprimée et recréée entre l'exécution de ces deux requêtes.  Le
   processus de hachage est également sensible aux différences d'architecture
   des machines ainsi que d'autres facettes de la plateforme.  De plus, il
   n'est pas sûr de partir du principe que queryid
   restera stable entre des versions majeures de
   PostgreSQL.
  
   Deux serveurs participant à une réplication basée sur le rejeu physique des
   journaux de transactions devraient avoir des valeurs de
   queryid identiques pour la même requête.
   Cependant, les systèmes de réplication logique ne promettent pas de conserver
   des réplicas identiques surtout les détails intéressants, donc
   queryid ne sera pas un identifiant utile pour
   accumuler les coûts dans un ensemble de réplicas logiques. En cas de doute,
   un test direct est recommandé.
  
   En règle général, il peut être supposé que les valeurs
   queryid sont stables entre des versions mineures
   de PostgreSQL, en supposant que les instances sont
   exécutées sur la même architecture matérielle et que les détails de
   métadonnées du catalogue correspondent. La compatibilité entre versions
   mineures ne sera cassée qu'en cas de dernière extrémité.
  
   Le symbole de paramètre utilité pour remplacer les constantes dans le texte
   représentatif de la requête démarre après le plus grand paramètre
   $n dans le texte de la
   requête originale, ou $1 s'il n'y en avait pas.  Il est
   intéressant de noter que dans certains cas il pourrait y avoir un symbole de
   paramètre caché qui affecte cette numérotation.  Par exemple,
   PL/pgSQL utilise des symbole de paramètre cachés
   pour insérer des valeurs de variables locales à la fonction dans les
   requêtes, ainsi un ordre PL/pgSQL comme
   SELECT i + 1 INTO j aurait un texte représentatif tel
   que SELECT i + $2.
  
   Les textes des requêtes sont conservées dans un fichier texte externe et ne
   consomment pas de mémoire partagée. De ce fait, même les textes très longs
   de requêtes peuvent être enregistrés avec succès. Néanmoins, si beaucoup de
   textes très longs de requêtes sont accumulées, le fichier externe peut
   devenir suffisamment gros pour ne plus être gérable. Si cela survient,
   comme méthode de restauration, pg_stat_statements peut
   choisir d'ignorer les textes de requêtes. Dans ce cas, le champ
   query apparaitra vide sur les lignes de la vue
   pg_stat_statements mais les statistiques associées
   seront préservées. Si cela arrive, réfléchissez à réduire la valeur du
   paramètre pg_stat_statements.max pour empêcher que cela
   ne recommence.
  
   plans et calls
   peuvent différer car les statistiques d'optimisation/planification et
   d'exécution sont mises à jours à leur fin respective, et seulement si elles
   ont réussi. Par exemple, si une requête est optimisée avec succès mais
   échoue sur la phase d'exécution, seules les statistiques
   d'optimisation/planification seront modifiées. Si
   l'optimisation/planification est ignorée parce qu'un plan en cache est
   utilisé, seules les statistiques d'exécution seront mises à jour.
  
pg_stat_statements_info
   Les statistiques du module pg_stat_statements lui-même
   sont tracées et rendues disponibles via une vue nommée
   pg_stat_statements_info. Cette vue contient une
   seule ligne. Les colonnes de la vue sont affichées dans Tableau F.21.
  
Tableau F.21. Colonnes de pg_stat_statements_info
Type de colonne Description  | 
|---|
        
       Nombre total de fois où les enregistrements de
         | 
        
       Horodatage de la dernière réinitialisation de toutes les statistiques de
         | 
pg_stat_statements_reset(userid Oid, dbid Oid, queryid bigint) returns void
     
    
      pg_stat_statements_reset annule les statistiques
      récupérées jusqu'à maintenant par
      pg_stat_statements correspondant aux
      userid, dbid et
      queryid indiqués. Si un de ces paramètres
      n'est pas spécifié, la valeur par défaut 0
      (invalide) est utilisée pour chacun d'entre eux et les statistiques qui
      correspondent avec les autres paramètres seront réinitialisées. Si
      aucun paramètre n'est spécifié ou si tous les paramètres spécifiés sont
      à 0 (invalide), elle annulera toutes les
      statistiques. Si toutes les statistiques de la vue
      pg_stat_statements sont annulées, cela va aussi
      réinitialiser les statistiques de la vue
      pg_stat_statements_info. Par défaut, cette
      fonction peut seulement être exécutée par les superutilisateurs.
      L'accès peut être donné à d'autres utilisateurs en utilisant la
      commande GRANT.
     
pg_stat_statements(showtext boolean) returns setof record
     
    
      La vue pg_stat_statements est basée sur une
      fonction également nommée pg_stat_statements.  Les
      clients peuvent appeler la fonction
      pg_stat_statements directement, et peuvent en
      spécifiant showtext := false ne pas récupérer le
      texte de la requête (ce qui veut dire que l'argument
      OUT qui correspond à la colonne
      query de la vue retournera des NULL).  Cette
      fonctionnalité est prévue pour le support d'outils externes qui
      pourraient vouloir éviter le surcoût de récupérer de manière répétée
      les textes des requêtes de longueur indéterminées.  De tels outils
      peuvent à la place eux-même mettre le premier texte de requête récupéré
      pour chaque entrée, puisque c'est déjà ce que fait
      pg_stat_statements lui-même, et ensuite récupérer
      les textes de requêtes uniquement si nécessaire.  Puisque le serveur
      stocke les textes de requête dans un fichier, cette approche pourrait
      réduire les entrée/sorties physiques pour des vérifications répétées
      des données de pg_stat_statements.
     
pg_stat_statements.max (integer)
     
    
      pg_stat_statements.max est le nombre maximum d'ordres
      tracés par le module (c'est-à-dire le nombre maximum de lignes dans la
      vue pg_stat_statements). Si un nombre
      supérieur d'ordres SQL distincts a été observé, c'est l'information sur
      les ordres les moins exécutés qui est ignorée. Le nombre de fois où une
      telle information est ignorée est consultable dans la vu
      pg_stat_statements_info. La valeur par défaut
      est 5000. Ce paramètre peut uniquement être positionné au démarrage du
      serveur.
     
pg_stat_statements.track (enum)
     
    
      pg_stat_statements.track contrôle quels sont les
      ordres comptabilisés par le module. Spécifiez top
      pour suivre les ordres de plus haut niveau (ceux qui sont soumis
      directement par les clients), all pour suivre
      également les ordres imbriqués (tels que les ordres invoqués dans les
      fonctions) ou none pour désactiver la récupération
      des statistiques sur les requêtes. La valeur par défaut est
      top. Seuls les superutilisateurs peuvent changer ce
      paramétrage.
     
pg_stat_statements.track_utility (boolean)
     
    
      pg_stat_statements.track_utility contrôle si les
      commandes utilitaires sont tracées par le module. Les commandes
      utilitaires sont toutes les commandes SQL sauf
      SELECT, INSERT,
      UPDATE, DELETE et
      MERGE. La valeur par
      défaut est on. Seuls les superutilisateurs peuvent
      modifier cette configuration.
     
pg_stat_statements.track_planning (boolean)
     
    
      pg_stat_statements.track_planning contrôle si les
      opérations d'optimisation/planification et leur durée sont tracées par
      ce module. Activer ce paramètre pourrait résulter en une perte visible
      de performance, spécialement quand les requêtes avec des structures
      identiques sont exécutées par de nombreuses connexions concurrentes, ce
      qui pousse à mettre à jour un petit nombre d'entrées de
      pg_stat_statements. La valeur par défaut est
      off. Seuls les superutilisateurs peuvent modifier
      cette configuration.
     
pg_stat_statements.save (boolean)
     
    
      pg_stat_statements.save précise s'il faut sauvegarder
      les statistiques lors des arrêts du serveur. S'il est
      off, alors les statistiques ne sont pas sauvegardées
      lors de l'arrêt ni rechargées au démarrage du serveur. La valeur par
      défaut est on. Ce paramètre peut uniquement être
      positionné dans le fichier postgresql.conf ou sur
      la ligne de commande du serveur.
     
   Le module a besoin de mémoire partagée supplémentaire proportionnelle à
   pg_stat_statements.max.  Notez que cette mémoire est
   consommée quand le module est chargé, même si
   pg_stat_statements.track est positionné à
   none.
  
   Ces paramètres doivent être définis dans
   postgresql.conf. Un usage courant pourrait être :
  
# postgresql.conf shared_preload_libraries = 'pg_stat_statements' compute_query_id = on pg_stat_statements.max = 10000 pg_stat_statements.track = all
bench=# SELECT pg_stat_statements_reset();
$ pgbench -i bench
$ pgbench -c10 -t300 bench
bench=# \x
bench=# SELECT query, calls, total_exec_time, rows, 100.0 * shared_blks_hit /
               nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
          FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5;
-[ RECORD 1 ]---+--------------------------------------------------------------------
query           | UPDATE pgbench_branches SET bbalance = bbalance + $1 WHERE bid = $2
calls           | 3000
total_exec_time | 25565.855387
rows            | 3000
hit_percent     | 100.0000000000000000
-[ RECORD 2 ]---+--------------------------------------------------------------------
query           | UPDATE pgbench_tellers SET tbalance = tbalance + $1 WHERE tid = $2
calls           | 3000
total_exec_time | 20756.669379
rows            | 3000
hit_percent     | 100.0000000000000000
-[ RECORD 3 ]---+--------------------------------------------------------------------
query           | copy pgbench_accounts from stdin
calls           | 1
total_exec_time | 291.865911
rows            | 100000
hit_percent     | 100.0000000000000000
-[ RECORD 4 ]---+--------------------------------------------------------------------
query           | UPDATE pgbench_accounts SET abalance = abalance + $1 WHERE aid = $2
calls           | 3000
total_exec_time | 271.232977
rows            | 3000
hit_percent     | 98.8454011741682975
-[ RECORD 5 ]---+--------------------------------------------------------------------
query           | alter table pgbench_accounts add primary key (aid)
calls           | 1
total_exec_time | 160.588563
rows            | 0
hit_percent     | 100.0000000000000000
bench=# SELECT pg_stat_statements_reset(0,0,s.queryid) FROM pg_stat_statements AS s
            WHERE s.query = 'UPDATE pgbench_branches SET bbalance = bbalance + $1 WHERE bid = $2';
bench=# SELECT query, calls, total_exec_time, rows, 100.0 * shared_blks_hit /
               nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
          FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5;
-[ RECORD 1 ]---+--------------------------------------------------------------------
query           | UPDATE pgbench_tellers SET tbalance = tbalance + $1 WHERE tid = $2
calls           | 3000
total_exec_time | 20756.669379
rows            | 3000
hit_percent     | 100.0000000000000000
-[ RECORD 2 ]---+--------------------------------------------------------------------
query           | copy pgbench_accounts from stdin
calls           | 1
total_exec_time | 291.865911
rows            | 100000
hit_percent     | 100.0000000000000000
-[ RECORD 3 ]---+--------------------------------------------------------------------
query           | UPDATE pgbench_accounts SET abalance = abalance + $1 WHERE aid = $2
calls           | 3000
total_exec_time | 271.232977
rows            | 3000
hit_percent     | 98.8454011741682975
-[ RECORD 4 ]---+--------------------------------------------------------------------
query           | alter table pgbench_accounts add primary key (aid)
calls           | 1
total_exec_time | 160.588563
rows            | 0
hit_percent     | 100.0000000000000000
-[ RECORD 5 ]---+--------------------------------------------------------------------
query           | vacuum analyze pgbench_accounts
calls           | 1
total_exec_time | 136.448116
rows            | 0
hit_percent     | 99.9201915403032721
bench=# SELECT pg_stat_statements_reset(0,0,0);
bench=# SELECT query, calls, total_exec_time, rows, 100.0 * shared_blks_hit /
               nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
          FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5;
-[ RECORD 1 ]---+-----------------------------------------------------------------------------
query           | SELECT pg_stat_statements_reset(0,0,0)
calls           | 1
total_exec_time | 0.189497
rows            | 1
hit_percent     |
-[ RECORD 2 ]---+-----------------------------------------------------------------------------
query           | SELECT query, calls, total_exec_time, rows, $1 * shared_blks_hit /          +
                |                nullif(shared_blks_hit + shared_blks_read, $2) AS hit_percent+
                |           FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT $3
calls           | 0
total_exec_time | 0
rows            | 0
hit_percent     |
  
   Takahiro Itagaki <itagaki.takahiro@oss.ntt.co.jp>. La
   normalisation des requêtes a été ajoutée par Peter Geoghegan
   <peter@2ndquadrant.com>.