Comprendiamo i piani delle query PostgreSQL in modo ancora più conveniente

Sei mesi fa abbiamo presentato explain.tensor.ru — pubblico servizio per l'analisi e la visualizzazione dei piani di query per PostgreSQL.

Comprendiamo i piani delle query PostgreSQL in modo ancora più conveniente

Negli ultimi mesi abbiamo fatto su di esso una relazione a PGConf.Russia 2020, abbiamo preparato un articolo riassuntivo sull'ottimizzazione delle query SQL basato sulle raccomandazioni che fornisce… ma la cosa più importante è che abbiamo raccolto i vostri feedback e osservato casi d'uso reali.

E ora siamo pronti a parlare delle nuove funzionalità che potete utilizzare.

Supporto per diversi formati di piano

Piano dal log, insieme alla query

Selezioniamo direttamente dalla console l'intero blocco, a partire dalla riga con Query Text, con tutti gli spazi iniziali:

        Query Text: INSERT INTO  dicquery_20200604  VALUES ($1.*) ON CONFLICT (query)
                           DO NOTHING;
        Insert on dicquery_20200604  (cost=0.00..0.05 rows=1 width=52) (actual time=40.376..40.376 rows=0 loops=1)
          Conflict Resolution: NOTHING
          Conflict Arbiter Indexes: dicquery_20200604_pkey
          Tuples Inserted: 1
          Conflicting Tuples: 0
          Buffers: shared hit=9 read=1 dirtied=1
          ->  Result  (cost=0.00..0.05 rows=1 width=52) (actual time=0.001..0.001 rows=1 loops=1)

… e incolliamo tutto ciò che abbiamo copiato direttamente nel campo per il piano, senza separare nulla:

Comprendiamo i piani delle query PostgreSQL in modo ancora più conveniente

Alla fine otteniamo un bonus al piano analizzato anche con una scheda «contesto», dove la nostra query è presentata in tutto il suo splendore:

Comprendiamo i piani delle query PostgreSQL in modo ancora più conveniente

JSON e YAML

EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
SELECT * FROM pg_class;

"[
  {
    "Plan": {
      "Node Type": "Seq Scan",
      "Parallel Aware": false,
      "Relation Name": "pg_class",
      "Alias": "pg_class",
      "Startup Cost": 0.00,
      "Total Cost": 1336.20,
      "Plan Rows": 13804,
      "Plan Width": 539,
      "Actual Startup Time": 0.006,
      "Actual Total Time": 1.838,
      "Actual Rows": 10266,
      "Actual Loops": 1,
      "Shared Hit Blocks": 646,
      "Shared Read Blocks": 0,
      "Shared Dirtied Blocks": 0,
      "Shared Written Blocks": 0,
      "Local Hit Blocks": 0,
      "Local Read Blocks": 0,
      "Local Dirtied Blocks": 0,
      "Local Written Blocks": 0,
      "Temp Read Blocks": 0,
      "Temp Written Blocks": 0
    },
    "Planning Time": 5.135,
    "Triggers": [
    ],
    "Execution Time": 2.389
  }
]"

Che sia con le virgolette esterne, come copia pgAdmin, o senza - mettiamo nello stesso campo, alla fine - bellezza:

Comprendiamo i piani delle query PostgreSQL in modo ancora più conveniente

Visualizzazione avanzata

Tempo di pianificazione / Tempo di esecuzione

Ora è più chiaro dove è andato il tempo aggiuntivo durante l'esecuzione della query:

Comprendiamo i piani delle query PostgreSQL in modo ancora più conveniente

I/O Timing

A volte ci si trova ad affrontare situazioni in cui il piano sembra non aver consumato molte risorse in lettura e scrittura, ma il tempo di esecuzione sembra essere eccessivamente lungo.

Qui bisogna dire: "Oh, probabilmente in quel momento il disco sul server era troppo sovraccarico, quindi ci è voluto così tanto tempo per leggere!" Ma non è molto preciso…

Ma è possibile definirlo in modo assolutamente affidabile. Il fatto è che tra le opzioni di configurazione del server PG ci sono track_io_timing:

Attiva la misurazione del tempo delle operazioni di input/output. Questa opzione è disabilitata per impostazione predefinita, poiché richiede di interrogare continuamente il tempo attuale dal sistema operativo, il che può rallentare notevolmente le prestazioni su alcune piattaforme. Per stimare il costo della misurazione del tempo sulla tua piattaforma, puoi utilizzare l'utility pg_test_timing. È possibile ottenere statistiche di input/output tramite la vista pg_stat_database, nell'output di EXPLAIN (quando viene utilizzato il parametro BUFFERS) e tramite la vista pg_stat_statements.

Questo parametro può essere attivato anche all'interno di una sessione locale:

SET track_io_timing = TRUE;

E ora la parte più interessante: abbiamo imparato a comprendere e visualizzare questi dati tenendo conto di tutte le trasformazioni dell'albero di esecuzione:

Comprendiamo i piani delle query PostgreSQL in modo ancora più conveniente

Qui possiamo notare che dei 0.790ms totali di tempo di esecuzione, 0.718ms sono stati impiegati per leggere una pagina di dati, 0.044ms per scrivere la stessa, mentre per tutta l'altra attività utile è stato speso solo 0.028ms!

Il futuro con PostgreSQL 13

Puoi trovare una panoramica completa delle novità in un articolo dettagliato, mentre noi ci concentriamo specificamente sulle modifiche nei piani.

Buffer di pianificazione

La gestione delle risorse allocate al pianificatore è stata riflessa in un altro patch, non correlato a pg_stat_statements. EXPLAIN con l'opzione BUFFERS riporterà il numero di buffer utilizzati nella fase di pianificazione:

 Seq Scan on pg_class (righe effettive=386 cicli=1)
   Buffers: shared hit=9 read=4
 Tempo di pianificazione: 0.782 ms
   Buffers: shared hit=103 read=11
 Tempo di esecuzione: 0.219 ms

Comprendiamo i piani delle query PostgreSQL in modo ancora più conveniente

Ordinamento incrementale

Nei casi in cui è necessaria l'ordinamento su più chiavi (k1, k2, k3…), il pianificatore può ora avvalersi della conoscenza che i dati sono già ordinati secondo alcune delle prime chiavi (ad esempio, k1 e k2). In questo caso, non è necessario riordinare tutti i dati, ma è possibile suddividerli in gruppi consecutivi con gli stessi valori di k1 e k2 e 'completare' l'ordinamento secondo la chiave k3.

In questo modo, tutta l'ordinamento si suddivide in diverse ordinamenti consecutivi di dimensioni inferiori. Ciò riduce la quantità di memoria necessaria e consente anche di restituire i primi dati prima che l'intera ordinamento sia completamente completata.

 Ordinamento Incrementale (righe attuali=2949857 cicli=1)
   Chiave di Ordinamento: ticket_no, passenger_id
   Chiave Preordinata: ticket_no
   Gruppi di ordinamento completi: 92184 Metodo di Ordinamento: quicksort Memoria: avg=31kB peak=31kB
   ->  Scansione Indice utilizzando tickets_pkey su tickets (righe attuali=2949857 cicli=1)
 Tempo di Pianificazione: 2.137 ms
 Tempo di Esecuzione: 2230.019 ms

Comprendiamo i piani delle query PostgreSQL in modo ancora più conveniente
Comprendiamo i piani delle query PostgreSQL in modo ancora più conveniente

Miglioramenti UI/UX

Screenshot, sono ovunque!

Ora è possibile prendere rapidamente uno screenshot della scheda negli appunti per l'intera larghezza e profondità della scheda — «mirino» in alto a destra:

Comprendiamo i piani delle query PostgreSQL in modo ancora più conveniente

In effetti, la maggior parte delle immagini per questa pubblicazione è stata ottenuta proprio in questo modo.

Raccomandazioni sui nodi

Non solo ce ne sono di più, ma per ognuna è possibile leggere dettagliatamente nell'articolo, seguendo il link:

Comprendiamo i piani delle query PostgreSQL in modo ancora più conveniente

Rimozione dall'archivio

Alcuni hanno richiesto di aggiungere la possibilità di eliminare "completamente" anche i piani non pubblicabili in archivio — per favore, basta premere l'icona corrispondente:

Comprendiamo i piani delle query PostgreSQL in modo ancora più conveniente

E non dimentichiamo che abbiamo un gruppo di supporto, dove è possibile scrivere osservazioni e suggerimenti.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster