Come faccio a sapere quanto è lunga la mia query PostgreSQL?


35

Ho un'idea abbastanza decente di quante righe verrà effettivamente elaborata dalla mia query SELECT ... INTO (ad esempio, so quante si materializzeranno).

Capisco che Postgres non mi dirà completezza percentuale, c'è un modo (sepolto in profondità nei registri, nelle tabelle di sistema o altro) che posso scoprire quante righe sono state pompate nella tabella di destinazione o sono state lette dalla query SELECT ?

Risposte:


33

Come ha detto Daniel Vérité, non sembra esserci una soluzione generica. Quando si caricano dati in una tabella da un file, è possibile utilizzare la seguente tecnica per ottenere l'avanzamento del caricamento.

Barra di avanzamento della console di comando COPIA

Crea una tabella vuota.

CREATE TABLE mytest (n int);

Crea un file di dati con 10 milioni di righe per il caricamento nella tabella.

$ seq 10000000 > /tmp/data.txt

Carica i dati dal file nella tabella e visualizza una barra di avanzamento.

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

dimostrazione

inserisci qui la descrizione dell'immagine

Come funziona

Utilizzando l'opzione STDIN dei comandi di copia, possiamo inserire i dati per l'operazione di copia da un altro processo. Il comando pv emetterà un file e ne traccerà l'avanzamento visualizzando una barra di avanzamento, ETA, tempo totale trascorso e la velocità di trasferimento dei dati.

Barra di avanzamento grafica del comando COPIA

Utilizzando la stessa tecnica generale potremmo visualizzare una barra di avanzamento in un'applicazione grafica o in un'applicazione basata sul web. Utilizzando python, ad esempio, il modulo psycopg2 consente di chiamare il comando copy con un oggetto file di propria scelta. È quindi possibile tenere traccia di quanto oggetto file è stato letto e visualizzare una barra di avanzamento.


2
Non avevo mai incontrato il pvcomando prima, e non era installato sul mio server Debian per impostazione predefinita, ma è nel repository. La descrizione dice "pv (Pipe Viewer) può essere inserito in qualsiasi normale pipeline tra due processi per dare un'indicazione visiva della velocità con cui i dati passano". Un comando molto utile!
Richard Turner,

27

Non sembra esserci un metodo generico supportato, ma ci sono alcuni trucchi che possono essere utilizzati in contesti limitati per valutare lo stato di avanzamento di una singola query. Qui ce ne sono un po.

sequenze

Quando una query SELECT o UPDATE ne include una nextval(sequence_name)o un INSERT ha una colonna di destinazione con un nextvalvalore predefinito, il valore della sequenza corrente può essere ripetutamente interrogato in un'altra sessione con SELECT sequence_name.last_value. Funziona perché le sequenze non sono limitate dalle transazioni. Quando il piano di esecuzione è tale che la sequenza viene incrementata linearmente durante la query, può essere utilizzata come indicatore di avanzamento.

pgstattuple

Il modulo contrib di pgstattuple fornisce funzioni che possono sbirciare direttamente le pagine dei dati. Sembra che quando le tuple vengono inserite in una tabella vuota e non ancora impegnate, vengono contate nel dead_tuple_countcampo dalla pgstattuplefunzione.

Demo con 9.1: crea una tabella vuota

CREATE TABLE tt AS (n numeric);

Inseriamo 10 M righe al suo interno:

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

In un'altra sessione, controlla pgstattuple ogni secondo durante l'inserimento:

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

risultati:

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

Ritorna a 0 al termine dell'inserto (tutte le tuple diventano visibili e attive).

Questo trucco può essere utilizzato anche quando la tabella non è stata creata di recente, ma dead_tuple_countè probabile che l'iniziale abbia un valore diverso da zero e può anche cambiare contemporaneamente se altre attività di scrittura come l'autovacuum sono in corso (presumibilmente? Non sei sicuro di quale livello di concorrenza da aspettarsi con autovacuum).

Tuttavia, non può essere utilizzato se la tabella viene creata dall'istruzione stessa ( CREATE TABLE ... AS SELECTo SELECT * INTO newtable), poiché la creazione viene eseguita. La soluzione alternativa sarebbe quella di creare la tabella senza righe (aggiungere LIMIT 0) e compilarla nella transazione successiva.

Nota che pgstattuplenon è gratuito: scansiona l'intero tavolo ad ogni chiamata. Inoltre è limitato ai super utenti.

Contatore personalizzato

Nel blog di Pavel Stehule, fornisce una funzione contatore implementata in C che genera AVVISI a un numero specificato di esecuzioni. Devi combinare la funzione con la query in qualche modo per consentire all'esecutore di chiamarla. Gli avvisi vengono inviati durante la query e non necessitano di una sessione separata, ma solo di un client SQL che li visualizza ( psqlessendo il candidato ovvio).

Esempio di INSERT INTO rielaborato per generare avvisi:

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

Domanda correlata su StackOverflow, per funzioni:
come segnalare i progressi dalla funzione PostgreSQL a esecuzione prolungata al client

Opzioni future?

A partire da maggio 2017, c'è una promettente patch inviata alla comunità degli sviluppatori: [PATCH v2] Comando progress per monitorare la progressione di query SQL a esecuzione prolungata

che potrebbe finire come una soluzione generica in PostgreSQL 11 o versioni successive. Gli utenti che desiderano partecipare alle funzionalità work-in-progress possono applicare l'ultima versione della patch e provare il PROGRESScomando proposto .


3

Fino a quando la funzionalità del rapporto sullo stato di avanzamento non verrà estesa, come menzionato da @AmirAliAkbari nella sua risposta, ecco una soluzione alternativa a livello di sistema operativo.

Funziona solo su Linux, ma probabilmente esistono soluzioni simili facilmente googlabili per qualsiasi sistema operativo.

Il grande vantaggio anche svantaggio del PostgreSQL, che tutti i suoi backends sono semplici processi single-threaded, utilizzando lseek(), read()e write()per manipolare i file di tabella, mentre stanno interagendo sul mem e serrature condivisa.

Di conseguenza, tutti i suoi processi di backend funzionano sempre su una singola query, che può essere facilmente trovata e facilmente straced.

Innanzitutto, è possibile visualizzare il PID backend da 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 terza colonna è il pid. In PostgreSQL, è lo stesso del processo pid Linux del backend.

Successivamente, puoi stracciarlo, ad esempio con un strace -p 20019 -s 8192: ( -s 8192è utile perché postgresql funziona con blocchi lunghi 8192 byte).

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>"...

I significati:

  • sendtoaccade se il back-end risponde a un client. Nell'esempio, risponde al risultato di una INSERTquery.
  • recvfromsuccede se il backend ottiene qualcosa da un client. In genere è una nuova query, nell'esempio, ancora un'altra INSERT.
  • lseek succede se il backend cambia posizione in un file di tabella.
  • read succede se il backend legge un blocco da un file di tabella.
  • write succede se il backend scrive un blocco in un file di tabella.

Nel caso di reade write, puoi anche vedere il contenuto di quel blocco nella tabella. Può aiutare molto a capire, cosa sta facendo e dove si trova.

Nel caso di recvfrom, puoi vedere la query effettiva che cosa ha il backend.


2

Come detto in altre risposte, attualmente non esiste un modo diretto per riferire sui progressi in generale.

PostgreSQL ha la capacità di segnalare l'avanzamento di determinati comandi durante l'esecuzione del comando. Attualmente, l'unico comando che supporta la segnalazione dei progressi è VACUUM. Questo potrebbe essere ampliato in futuro.

Tuttavia, a partire dalla 9.6, ogni volta che VACUUMè in esecuzione, la pg_stat_progress_vacuumvista conterrà una riga per ciascun back-end (inclusi i processi di lavoro con autovacuum) che sta attualmente eseguendo l'aspirazione. Ulteriori dettagli in merito pg_stat_progress_vacuumsono disponibili nella documentazione: 27.4 Rapporti di avanzamento .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.