Comment savoir à quelle distance se trouve ma requête PostgreSQL?

35

J'ai une assez bonne idée du nombre de lignes que ma requête SELECT ... INTO traitera réellement (par exemple, je sais combien de lignes vont se matérialiser).

Je comprends que Postgres ne m'indique pas le pourcentage d'exhaustivité. Existe-t-il un moyen (enfoui au fond de journaux, de tables système ou autre) de savoir combien de lignes ont été pompées dans la table de destination ou lues par la requête SELECT ?

Mark Elliot
la source

Réponses:

33

Comme l'a mentionné Daniel Vérité, il ne semble pas exister de solution générique. Lors du chargement de données dans une table à partir d'un fichier, la technique suivante peut être utilisée pour obtenir la progression du chargement.

Barre de progression de la console de commande COPY

Créez une table vide.

CREATE TABLE mytest (n int);

Créez un fichier de données avec 10 millions de lignes à charger dans la table.

$ seq 10000000 > /tmp/data.txt

Chargez les données du fichier dans la table et affichez une barre de progression.

$ pv /tmp/data.txt | psql -c "COPY mytest FROM STDIN;"

Démo

entrez la description de l'image ici

Comment ça marche

En utilisant l'option STDIN des commandes de copie, nous pouvons introduire les données pour l'opération de copie à partir d'un autre processus. La commande pv produira un fichier et suivra sa progression en affichant une barre de progression, l'ETA, le temps total écoulé et le taux de transfert des données.

Barre de progression graphique de la commande COPY

En utilisant la même technique générale, nous pourrions afficher une barre de progression dans une application graphique ou une application Web. En utilisant python par exemple, le module psycopg2 vous permet d’appeler la commande copy avec un objet fichier de votre choix. Vous pouvez ensuite suivre la quantité de votre objet fichier qui a été lue et afficher une barre de progression.

Marwan Alsabbagh
la source
2
Je n'avais jamais rencontré la pvcommande auparavant, et elle n'était pas installée par défaut sur mon serveur Debian, mais c'est dans le référentiel. La description indique que "pv (Pipe Viewer) peut être inséré dans tout pipeline normal entre deux processus pour donner une indication visuelle de la vitesse à laquelle les données transitent". Une commande très utile!
Richard Turner
27

Il ne semble pas exister de méthode générique prise en charge, mais certaines astuces peuvent être utilisées dans des contextes limités pour évaluer la progression d'une requête individuelle. En voici quelques uns.

Des séquences

Lorsqu'une requête SELECT ou UPDATE inclut une requête nextval(sequence_name)ou qu'une colonne INSERT possède une colonne de destination avec une nextvalvaleur par défaut, la valeur de la séquence actuelle peut être interrogée de manière répétée dans une autre session SELECT sequence_name.last_value. Cela fonctionne parce que les séquences ne sont pas liées par des transactions. Lorsque le plan d'exécution est tel que la séquence est incrémentée de manière linéaire au cours de la requête, il peut être utilisé comme indicateur de progression.

pgstattuple

Le module contrib de pgstattuple fournit des fonctions qui permettent d’observer directement les pages de données. Il semble que lorsque les n-uplets sont insérés dans une table vide et non encore validés, ils sont comptés dans le dead_tuple_countchamp à partir de la pgstattuplefonction.

Démo avec 9.1: créer une table vide

CREATE TABLE tt AS (n numeric);

Insérons 10 millions de lignes dedans:

INSERT INTO tt SELECT * FROM random() from generate_series(1,10000000);

Dans une autre session, vérifiez pgstattuple toutes les secondes lors de l'insertion:

$ while true;
   do psql -Atc "select dead_tuple_count from pgstattuple('tt')";
   sleep 1;
  done

Résultats:

0
69005
520035
1013430
1492210
1990415
2224625
2772040
3314460
3928660
4317345
4743770
5379430
6080950
6522915
7190395
7953705
8747725
9242045
0

Il retombe à 0 lorsque l'insertion est terminée (tous les n-uplets deviennent visibles et vivants).

Cette astuce peut également être utilisée lorsque la table n'est pas fraîchement créée, mais l'initiale dead_tuple_countaura probablement une valeur différente de zéro. Elle peut également changer simultanément si d'autres activités d'écriture telles que autovacuum sont en cours (vraisemblablement? Vous ne savez pas quel niveau de simultanéité à attendre avec autovacuum).

Cependant, il ne peut pas être utilisé si la table est créée par la déclaration elle-même ( CREATE TABLE ... AS SELECTou SELECT * INTO newtable), car la création est effectuée en transaction. La solution de contournement serait de créer la table sans lignes (add LIMIT 0) et de la renseigner dans la transaction suivante.

Notez que ce pgstattuplen'est pas gratuit: il scanne toute la table à chaque appel. En outre, il est limité aux superutilisateurs.

Compteur personnalisé

Dans le blog de Pavel Stehule, il fournit une fonction de compteur implémentée en C qui lève les AVIS à un nombre spécifié d'exécutions. Vous devez combiner la fonction avec la requête pour permettre à l’exécuteur de l’appeler. Les avis sont envoyés pendant la requête et ils n'ont pas besoin d'une session séparée, mais uniquement d'un client SQL qui les affiche ( psqlle candidat évident).

Exemple d'insertion dans modifiée pour émettre des avis:

/* transformation */
INSERT INTO destination_table
   SELECT (r).*
  FROM (SELECT counter(to_destination_table(_source), 1000, true) r
           FROM source _source) x

Question connexe sur stackoverflow, pour les fonctions:
Comment signaler la progression d'une fonction PostgreSQL de longue durée au client

Options futures?

Depuis mai 2017, un correctif prometteur a été soumis à la communauté des développeurs: commande [PATCH v2] Progress pour surveiller la progression des requêtes SQL de longue durée.

qui pourrait aboutir à une solution générique dans PostgreSQL 11 ou version ultérieure. Les utilisateurs qui ont envie de participer à des fonctionnalités de travail en cours peuvent appliquer la dernière version du correctif et essayer la PROGRESScommande proposée .

Daniel Vérité
la source
3

Jusqu'à ce que la fonctionnalité de rapport d'avancement ne soit pas étendue, comme l'a mentionné @AmirAliAkbari dans sa réponse, voici une solution de contournement au niveau du système d'exploitation.

Cela ne fonctionne que sur les Linux, mais il existe probablement des solutions similaires facilement compatibles avec tous les systèmes d'exploitation.

Le plus grand avantage et aussi inconvénient de PostgreSQL, que tous ses backends sont simples processus mono-thread, en utilisant lseek(), read()et write()pour manipuler leurs fichiers de table, alors qu'ils sont en interaction sur mem partagée et les serrures.

Cela a pour résultat que tous ses processus backend fonctionnent toujours sur une requête unique, qui peut être facilement trouvée et facilement straced.

Tout d’abord, vous pouvez voir le PID principal à partir d’un SELECT * FROM pg_stat_activity;:

29805270 | dbname  | 20019 |    16384 | username  |                  |             |                 |          -1 | 2018-09-19 21:31:57.68234+02  | 2018-09-19 21:31:59.435376+02 | 2018-09-\
20 00:34:30.892382+02 | 2018-09-20 00:34:30.892386+02 | Client          | ClientRead | active              |       92778 |        92778 |  INSERT INTO ...something...

La troisième colonne est le pid. Dans PostgreSQL, il est identique au pid de processus Linux du backend.

Ensuite, vous pouvez le tracer, par exemple avec un strace -p 20019 -s 8192: ( -s 8192est utile car postgresql fonctionne avec des blocs longs de 8192 octets).

sendto(10, "C\0\0\0\17INSERT 0 1\0Z\0\0\0\5T", 22, 0, NULL, 0) = 22
recvfrom(10, "Q\0\0\1\267 INSERT <removed by @peterh>", 8192, 0, NULL, NULL) = 440
sendto(10, "C\0\0\0\17INSERT 0 1\0Z\0\0\0\5T", 22, 0, NULL, 0) = 22
lseek(298, 343634345)...
read(298, "<block data which was read in>"....
write(298, "<block data which was written out>"...

Les significations:

  • sendtose passe-t-il si le serveur répond à un client? Dans l'exemple, il répond au résultat d'une INSERTrequête.
  • recvfromse produit si le backend obtient quelque chose d'un client. Il s'agit généralement d'une nouvelle requête, dans l'exemple, encore d'une autre INSERT.
  • lseek Cela se produit si le serveur change de position dans un fichier de table.
  • read se produit si le backend lit un bloc dans un fichier table.
  • write se passe-t-il si le serveur écrit un bloc dans un fichier table?

Dans le cas de readet write, vous pouvez également voir le contenu de ce bloc dans la table. Il peut être très utile de comprendre ce qu’il fait et où il se trouve.

Dans le cas de recvfrom, vous pouvez voir la requête réelle sur le backend.

Peter dit de réintégrer Monica
la source
2

Comme indiqué dans d’autres réponses, il n’existe actuellement aucun moyen direct de faire rapport sur les progrès accomplis.

PostgreSQL a la capacité de rendre compte de la progression de certaines commandes lors de leur exécution. Actuellement, la seule commande qui prend en charge le rapport d'avancement est VACUUM. Cela pourrait être étendu à l'avenir.

Cependant, à partir de 9.6, VACUUMla pg_stat_progress_vacuumvue contiendra une ligne pour chaque serveur (y compris les processus de travail autovacuum) à chaque fois qu’elle est en cours d’exécution . Vous trouverez plus de détails sur la pg_stat_progress_vacuumdocumentation dans la documentation: 27.4 Rapports d’avancement .

Amir Ali Akbari
la source