Cosa mi spiega esattamente PostgreSQL?


116

L'output di spiegazione di MySQL è piuttosto semplice. PostgreSQL è un po 'più complicato. Nemmeno io sono riuscito a trovare una buona risorsa che lo spieghi.

Puoi descrivere cosa esattamente spiegare sta dicendo o almeno indicarmi una buona risorsa?

Risposte:


50

Anche Explaining_EXPLAIN.pdf potrebbe aiutare.


64
Sono sconcertato dal motivo per cui la gente pensa che i deck diapositive costituiscano una buona documentazione tecnica. Un video del discorso potrebbe essere utile, ma la densità di informazioni di quella diapositiva è molto vicina allo zero. Nelle prime sei diapositive (1/5 del totale), c'è esattamente 1 frase di contenuto tecnico: "• EXPLAIN funziona su qualsiasi DML non solo su SELECT (cioè UPDATE, DELETE e INSERT)". Il mio più grande malinteso è cosa significhi tempo di "avvio", e questo non è spiegato da nessuna parte in queste 30 diapositive.
Mark E. Haase

80

La parte che ho sempre trovato confusa è il costo di avvio rispetto al costo totale. Lo cerco su Google ogni volta che me ne dimentico, il che mi riporta qui, il che non spiega la differenza, motivo per cui sto scrivendo questa risposta. Questo è ciò che ho raccolto dalla documentazione di PostgresEXPLAIN , spiegato a quanto ho capito.

Ecco un esempio tratto da un'applicazione che gestisce un forum:

EXPLAIN SELECT * FROM post LIMIT 50;

Limit  (cost=0.00..3.39 rows=50 width=422)
  ->  Seq Scan on post  (cost=0.00..15629.12 rows=230412 width=422)

Ecco la spiegazione grafica di PgAdmin:

spiegazione grafica della prima query

(Quando utilizzi PgAdmin, puoi puntare il mouse su un componente per leggere i dettagli del costo.)

Il costo è rappresentato come una tupla, ad esempio il costo di LIMITis cost=0.00..3.39e il costo della scansione sequenziale postè cost=0.00..15629.12. Il primo numero nella tupla è il costo di avvio e il secondo numero è il costo totale . Poiché ho usato EXPLAINe non EXPLAIN ANALYZE, questi costi sono stime, non misure effettive.

  • Il costo di avvio è un concetto complicato. Essa non si limita a rappresentare la quantità di tempo prima che tale componente si avvia . Rappresenta la quantità di tempo che intercorre tra l'inizio dell'esecuzione del componente (lettura dei dati) e il momento in cui il componente restituisce la prima riga .
  • Il costo totale è l'intero tempo di esecuzione del componente, da quando inizia a leggere i dati a quando termina la scrittura dell'output.

Come complicazione, i costi di ogni nodo "genitore" includono i costi dei suoi nodi figli. Nella rappresentazione testuale, l'albero è rappresentato dal rientro, ad esempio LIMITè un nodo genitore ed Seq Scanè il suo figlio. Nella rappresentazione PgAdmin, le frecce puntano da figlio a genitore, la direzione del flusso di dati, il che potrebbe essere controintuitivo se si ha familiarità con la teoria dei grafi.

La documentazione dice che i costi sono comprensivi di tutti i nodi figlio, ma si noti che il costo totale del genitore 3.39è molto inferiore al costo totale del figlio 15629.12. Il costo totale non è comprensivo perché un componente come LIMITnon ha bisogno di elaborare l'intero input. Vedi l' EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000 LIMIT 2;esempio nella documentazione di PostgresEXPLAIN .

Nell'esempio sopra, il tempo di avvio è zero per entrambi i componenti, perché nessuno dei componenti deve eseguire alcuna elaborazione prima di iniziare a scrivere righe: una scansione sequenziale legge la prima riga della tabella e la emette. Il LIMITlegge la sua prima riga e poi la emette.

Quando un componente dovrebbe eseguire molte elaborazioni prima di poter iniziare a produrre righe? Ci sono molte possibili ragioni, ma diamo un'occhiata a un chiaro esempio. Ecco la stessa query di prima ma ora contenente una ORDER BYclausola:

EXPLAIN SELECT * FROM post ORDER BY body LIMIT 50;

Limit  (cost=23283.24..23283.37 rows=50 width=422)
  ->  Sort  (cost=23283.24..23859.27 rows=230412 width=422)
        Sort Key: body
        ->  Seq Scan on post  (cost=0.00..15629.12 rows=230412 width=422)

E graficamente:

spiegazione grafica della seconda query

Ancora una volta, la scansione sequenziale postnon ha alcun costo di avvio: inizia immediatamente l'output delle righe. Ma l'ordinamento ha un costo di avvio significativo 23283.24perché deve ordinare l'intera tabella prima di poter produrre anche una singola riga . Il costo totale dell'ordinamento 23859.27è solo leggermente superiore al costo di avvio, riflettendo il fatto che una volta che l'intero set di dati è stato ordinato, i dati ordinati possono essere emessi molto rapidamente.

Si noti che il tempo di avvio di LIMIT 23283.24è esattamente uguale al tempo di avvio dell'ordinamento. Questo non è perché esso LIMITstesso ha un tempo di avvio elevato. In realtà ha un tempo di avvio pari a zero da solo, ma EXPLAINaccumula tutti i costi del figlio per ogni genitore, quindi il LIMITtempo di avvio include la somma dei tempi di avvio dei suoi figli.

Questo raggruppamento dei costi può rendere difficile la comprensione del costo di esecuzione di ogni singolo componente. Ad esempio, il nostro LIMITha un tempo di avvio pari a zero, ma a prima vista non è ovvio. Per questo motivo, molte altre persone si sono collegate a spiegare.depesz.com , uno strumento creato da Hubert Lubaczewski (aka depesz) che aiuta a capire EXPLAIN, tra le altre cose, sottraendo i costi dei figli dai costi dei genitori. Cita alcune altre complessità in un breve post sul blog sul suo strumento.


4
Grazie per questo. Vorrei anche aggiungere un visualizzatore di spiegazioni che fa un lavoro ancora migliore di visualizzare l'output (imo). tatiyants.com/pev
Jonathan Porter

Bella risposta. E il tuo commento secondo cui il costo di avvio include il tempo per la restituzione della prima riga mi ha aiutato a capire perché il costo di avvio per l'ordinamento non era solo 15629.12.
Joel Wigton,

43

Viene eseguito dal più rientrato al meno rientrato, e credo dal fondo del piano verso l'alto. (Quindi, se ci sono due sezioni rientrate, quella più in basso nella pagina viene eseguita per prima, quindi quando si incontrano viene eseguita l'altra, quindi viene eseguita la regola che le unisce.)

L'idea è che ad ogni passaggio ci siano 1 o 2 set di dati che arrivano e vengono elaborati da una regola. Se solo un set di dati, tale operazione viene eseguita su quel set di dati. (Ad esempio, scansiona un indice per capire quali righe vuoi, filtra un set di dati o ordinalo.) Se due, i due set di dati sono le due cose che sono ulteriormente rientrate e sono unite dalla regola che vedi. Il significato della maggior parte delle regole può essere ragionevolmente facilmente indovinato (in particolare se hai già letto un sacco di piani di spiegazione), tuttavia puoi provare a verificare i singoli elementi guardando nella documentazione o (più facilmente) semplicemente inserendo la frase Google insieme ad alcune parole chiave come EXPLAIN.

Questa ovviamente non è una spiegazione completa, ma fornisce un contesto sufficiente per poter solitamente capire quello che vuoi. Ad esempio, considera questo piano da un database reale:

explain analyze
select a.attributeid, a.attributevalue, b.productid
from orderitemattribute a, orderitem b
where a.orderid = b.orderid
and a.attributeid = 'display-album'
and b.productid = 'ModernBook';

------------------------------------------------------------------------------------------------------------------------------------------------------------

 Merge Join  (cost=125379.14..125775.12 rows=3311 width=29) (actual time=841.478..841.478 rows=0 loops=1)
   Merge Cond: (a.orderid = b.orderid)
   ->  Sort  (cost=109737.32..109881.89 rows=57828 width=23) (actual time=736.163..774.475 rows=16815 loops=1)
         Sort Key: a.orderid
         Sort Method:  quicksort  Memory: 1695kB
         ->  Bitmap Heap Scan on orderitemattribute a  (cost=1286.88..105163.27 rows=57828 width=23) (actual time=41.536..612.731 rows=16815 loops=1)
               Recheck Cond: ((attributeid)::text = 'display-album'::text)
               ->  Bitmap Index Scan on (cost=0.00..1272.43 rows=57828 width=0) (actual time=25.033..25.033 rows=16815 loops=1)
                     Index Cond: ((attributeid)::text = 'display-album'::text)
   ->  Sort  (cost=15641.81..15678.73 rows=14769 width=14) (actual time=14.471..16.898 rows=1109 loops=1)
         Sort Key: b.orderid
         Sort Method:  quicksort  Memory: 76kB
         ->  Bitmap Heap Scan on orderitem b  (cost=310.96..14619.03 rows=14769 width=14) (actual time=1.865..8.480 rows=1114 loops=1)
               Recheck Cond: ((productid)::text = 'ModernBook'::text)
               ->  Bitmap Index Scan on id_orderitem_productid  (cost=0.00..307.27 rows=14769 width=0) (actual time=1.431..1.431 rows=1114 loops=1)
                     Index Cond: ((productid)::text = 'ModernBook'::text)
 Total runtime: 842.134 ms
(17 rows)

Prova a leggerlo di persona e vedi se ha senso.

Quello che ho letto è che il database prima scansiona l' id_orderitem_productidindice, usandolo per trovare le righe da cui vuole orderitem, quindi ordina quel set di dati usando un quicksort (l'ordinamento usato cambierà se i dati non si adattano alla RAM), quindi lo mette da parte.

Successivamente, esegue la scansione orditematt_attributeid_idxper trovare le righe da cui desidera orderitemattributee quindi ordina il set di dati utilizzando un quicksort.

Quindi prende i due set di dati e li unisce. (Un merge join è una sorta di operazione di "compressione" in cui fa scorrere i due set di dati ordinati in parallelo, emettendo la riga unita quando corrispondono.)

Come ho detto, si lavora dalla parte interna del piano alla parte esterna, dal basso verso l'alto.



13

PgAdmin ti mostrerà una rappresentazione grafica del piano di spiegazione. Passare avanti e indietro tra i due può davvero aiutarti a capire cosa significa la rappresentazione del testo. Tuttavia, se vuoi solo sapere cosa farà, potresti essere in grado di usare sempre la GUI.



0

Se installi pgadmin, c'è un pulsante Spiega che oltre a fornire l'output di testo disegna diagrammi di ciò che sta accadendo, mostrando i filtri, gli ordinamenti e le fusioni di sottoinsiemi che trovo davvero utili per vedere cosa sta succedendo.

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.