Riga "Ricontrolla cond:" nei piani di query con una scansione dell'indice bitmap


21

Questo è uno spin-off dai commenti alla domanda precedente:

Usando PostgreSQL 9.4, sembra esserci sempre una Recheck Cond:riga dopo le scansioni dell'indice bitmap nei piani di query emessi da EXPLAIN.

Come EXPLAINnell'output della domanda di riferimento:

->  Bitmap Heap Scan on table_three  (cost=2446.92..19686.74 rows=8159 width=7)
      Recheck Cond: (("timestamp" > (now() - '30 days'::interval)) AND (client_id > 0))
      ->  BitmapAnd  (cost=2446.92..2446.92 rows=8159 width=0)
            ->  Bitmap Index Scan on table_one_timestamp_idx  (cost=0.00..1040.00 rows=79941 width=0)
                  Index Cond: ("timestamp" > (now() - '30 days'::interval))
            ->  Bitmap Index Scan on fki_table_three_client_id  (cost=0.00..1406.05 rows=107978 width=0)
                  Index Cond: (client_id > 0)

O nell'output di EXPLAIN ANALYZEper una tabella semplice, enorme (con pochissimo work_mem):

EXPLAIN ANALYZE SELECT * FROM aa WHERE a BETWEEN 100000 AND 200000;
Bitmap Heap Scan on aa  (cost=107.68..4818.05 rows=5000 width=4) (actual time=27.629..213.606 rows=100001 loops=1)
  Recheck Cond: ((a >= 100000) AND (a <= 200000))
  Rows Removed by Index Recheck: 758222
  Heap Blocks: exact=693 lossy=3732
  ->  Bitmap Index Scan on aai  (cost=0.00..106.43 rows=5000 width=0) (actual time=27.265..27.265 rows=100001 loops=1)
        Index Cond: ((a >= 100000) AND (a <= 200000))

Ciò significa che le condizioni dell'indice devono essere verificate una seconda volta dopo una scansione dell'indice bitmap?
Cos'altro possiamo imparare EXPLAINdall'output?

Risposte:


17

Come @Chris ha commentato correttamente sulla domanda di riferimento :

una piccola indagine sembra indicare che la condizione di ricontrollo è sempre stampata in EXPLAIN, ma in realtà viene eseguita solo quando work_memè abbastanza piccola da far perdere la bitmap. Pensieri? http://www.postgresql.org/message-id/464F3C5D.2000700@enterprisedb.com

Mentre questo è tutto vero e lo sviluppatore principale Heikki Linnakangas è una fonte di prima classe, il post risale al 2007 (Postgres 8.2). Ecco un post sul blog di Michael Paquier con una spiegazione dettagliata di Postgres 9.4 , dove l'output di EXPLAIN ANALYZEè stato migliorato con maggiori informazioni.

La Recheck Cond:linea è sempre lì per le scansioni dell'indice bitmap. L'output di base EXPLAINnon ci dirà di più. Otteniamo ulteriori informazioni da EXPLAIN ANALYZEcome si può vedere nella seconda citazione nella domanda:

Heap Blocks: exact=693 lossy=3732

Da un totale di 4425 pagine di dati (blocchi), 693 tuple memorizzate esattamente (inclusi i puntatori di tuple), mentre le altre 3732 pagine erano in perdita (solo la pagina di dati) nella bitmap. Ciò accade quando work_memnon è abbastanza grande per memorizzare esattamente l'intera bitmap creata dalla scansione dell'indice (senza perdita).

La condizione dell'indice deve essere ricontrollata per le pagine dalla condivisione con perdita, poiché la bitmap ricorda solo quali pagine recuperare e non le tuple esatte sulla pagina. Non tutte le tuple nella pagina passeranno necessariamente le condizioni dell'indice, è necessario ricontrollare effettivamente la condizione.

Questo è il thread sugli hacker pgsql in cui è stata discussa la nuova aggiunta . L'autore Etsuro Fujita fornisce una formula su come calcolare il minimo work_memper evitare voci bitmap con perdita e ricontrollare le condizioni che ne conseguono. Il calcolo non è affidabile per casi complessi con più scansioni bitmap, quindi non è stato utilizzato per l'output di numeri reali EXPLAIN. Può ancora servire da stima per casi semplici.

Linea aggiuntiva BUFFERS:

Inoltre, quando si esegue con l' BUFFERSopzione: EXPLAIN (ANALYZE, BUFFERS) ...viene aggiunta un'altra riga come:

Buffers: shared hit=279 read=79

Questo indica quanto della tabella sottostante (e dell'indice) è stato letto dalla cache ( shared hit=279) e quanto ha dovuto essere recuperato dal disco ( read=79). Se si ripete la query, la parte "read" in genere scompare per query non troppo grandi, poiché ora tutto viene memorizzato nella cache dopo la prima chiamata. La prima chiamata ti dice quanto è già stato memorizzato nella cache. Le chiamate successive mostrano quanto la tua cache può gestire (attualmente).

Ci sono più opzioni. Il manuale BUFFERSsull'opzione:

In particolare, includere il numero di blocchi condivisi colpiti, letti, sporcati e scritti, il numero di blocchi locali colpiti, letti, sporcati e scritti e il numero di blocchi temporanei letti e scritti.

Continua a leggere, c'è di più.
Ecco l'elenco delle opzioni di output nel codice sorgente .


10

Erwin, dato che questa era la nostra discussione nel thread dei commenti di prima, ho deciso di spingerlo un po 'più avanti ...

Ho una query molto semplice da una tabella di dimensioni ragionevoli. In genere ne ho sufficienti work_mem, ma in questo caso ho usato i comandi

SET work_mem = 64;

per impostare un molto piccolo work_meme

SET work_mem = default;

per impostare le mie work_memspalle in modo che siano sufficientemente grandi per la mia domanda.

SPIEGARE e ricontrollare le condizioni

Quindi, eseguendo la mia query con solo EXPLAINcome

EXPLAIN 
SELECT * FROM olap.reading_facts
WHERE meter < 20;

Ho ottenuto i risultati sia per basso che per alto work_mem:

Basso work_mem

Bitmap Heap Scan on reading_facts  (cost=898.92..85632.60 rows=47804 width=32)
  Recheck Cond: (meter < 20)
  ->  Bitmap Index Scan on idx_meter_reading_facts  (cost=0.00..886.96 rows=47804 width=0)
        Index Cond: (meter < 20)

alto work_mem

Bitmap Heap Scan on reading_facts  (cost=898.92..85632.60 rows=47804 width=32)
  Recheck Cond: (meter < 20)
  ->  Bitmap Index Scan on idx_meter_reading_facts  (cost=0.00..886.96 rows=47804 width=0)
        Index Cond: (meter < 20)

Per farla breve, EXPLAINsolo, come previsto, il piano di query indica che è possibile una condizione di ricontrollo, ma non possiamo sapere se verrà effettivamente calcolato.

SPIEGARE ANALISI e ricontrollare le condizioni

Quando includiamo ANALYZEnella query, i risultati ci informano di più su ciò che dobbiamo sapere.

Basso work_mem

Bitmap Heap Scan on reading_facts  (cost=898.92..85632.60 rows=47804 width=32) (actual time=3.130..13.946 rows=51840 loops=1)
  Recheck Cond: (meter < 20)
  Rows Removed by Index Recheck: 86727
  Heap Blocks: exact=598 lossy=836
  ->  Bitmap Index Scan on idx_meter_reading_facts  (cost=0.00..886.96 rows=47804 width=0) (actual time=3.066..3.066 rows=51840 loops=1)
        Index Cond: (meter < 20)

alto work_mem

Bitmap Heap Scan on reading_facts  (cost=898.92..85632.60 rows=47804 width=32) (actual time=2.647..7.247 rows=51840 loops=1)
  Recheck Cond: (meter < 20)
  Heap Blocks: exact=1434
  ->  Bitmap Index Scan on idx_meter_reading_facts  (cost=0.00..886.96 rows=47804 width=0) (actual time=2.496..2.496 rows=51840 loops=1)
        Index Cond: (meter < 20)

Ancora una volta, come previsto, l'inclusione di ci ANALYZErivela alcune informazioni molto importanti. In work_memminuscolo, vediamo che ci sono righe rimosse dal controllo dell'indice e che abbiamo lossyblocchi di heap.

Conclusione? (o la mancanza di)

Sfortunatamente, sembra che EXPLAINda solo non sia sufficiente sapere se un controllo dell'indice sarà effettivamente necessario perché alcuni degli ID di riga vengono eliminati a favore del mantenimento delle pagine durante la scansione dell'heap bitmap.

L'uso EXPLAIN ANALYZEva bene per diagnosticare i problemi con query di lunghezza moderata, ma nel caso in cui una query stia impiegando molto tempo per essere completata, l'esecuzione EXPLAIN ANALYZEper scoprire che l'indice bitmap si sta convertendo in perdita a causa di insufficiente work_memè ancora un vincolo difficile. Vorrei che ci fosse un modo per EXPLAINstimare la probabilità di questo evento dalle statistiche della tabella.

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.