PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Intestini di PostgreSQL:cos'è "resjunk"?

Al momento sto approfondendo il parser PostgreSQL, il rewriter di query e il pianificatore di query, come parte del lavoro sulla sicurezza a livello di riga per il progetto AXLE. Dato che ho notato che c'è un'ottima documentazione sulla struttura generale e sul flusso, ma non molto su alcuni dettagli, ho pensato di iniziare a postare su alcuni degli angoli più confusi.

Se non sei interessato al codice sorgente di PostgreSQL e al suo funzionamento interno, puoi interrompere la lettura ora.

resjunk

L'argomento di oggi è il termine "resjunk", che si riferisce a resjunk attributo dell'elenco di destinazioni. Vedrai questo termine in tutto il pianificatore e il riscrittore, di solito come presunta conoscenza. Il nome non è di grande aiuto.

resjunk le colonne sono descritte in src/backend/executor/execJunk.c , dove c'è un commento moderatamente dettagliato. Tuttavia, non spiega davvero le idee generali.

Il concetto è che a volte PostgreSQL ha bisogno di tenere traccia delle informazioni per tupla che non fanno parte dell'output della query. Potrebbe essere una chiave di ordinamento che non fa parte dell'elenco di selezione, un risultato intermedio di una sottoquery utilizzata come filtro e poi scartata, oppure potrebbe essere una colonna interna come ctid che non è esposto agli utenti.

I nodi del piano hanno elenchi di destinazioni:si tratta di elenchi delle colonne emesse da quel nodo del piano. Per un semplice test SELECT a, b FROM le colonne a e b apparirà nell'elenco di destinazione dell'indice o del nodo del piano seqscan per la query. Puoi osservarlo tu stesso abilitando la registrazione del piano, in base al seguente output tagliato:

regress=> CREATE TABLE 
regress=> SET enable_print_plan = on;
regress=> SET client_min_messages = debug;
regress=> SELECT a, b FROM test;
LOG:  plan:
DETAIL:     {PLANNEDSTMT 
   :commandType 1 
   :queryId 0 
   ....
   :planTree 
      {SEQSCAN 
      :startup_cost 0.00 
      :total_cost 29.40 
      :plan_rows 1940 
      :plan_width 12 
      :targetlist (
         {TARGETENTRY 
         :expr 
            {VAR 
            :varno 1 
            :varattno 1 
            ...
            :location 7
            }
         ...
         :resjunk false
         }
         {TARGETENTRY 
         :expr 
            {VAR 
            :varno 1 
            :varattno 2 
            ...
            :location 10
            }
         ....
         :resjunk false
         }
      )
      :qual  
      :lefttree  
      :righttree  
      :initPlan  
      :extParam (b)
      :allParam (b)
      :scanrelid 1
      }
   :rtable (
      {RTE 
      :alias  
      :eref 
         {ALIAS 
         :aliasname test 
         :colnames ("a" "b")
         }
      ...
      :selectedCols (b 9 10)
      :modifiedCols (b)
      }
   )
   ....
   }

Questo è il piano dettagliato per:

                       QUERY PLAN                       
--------------------------------------------------------
 Seq Scan on test  (cost=0.00..29.40 rows=1940 width=8)

In esso vedrai che il SELECT ha due voci nell'elenco di destinazione, una per ogni colonna. Nessuno dei due è resjunk poiché entrambi vengono emessi dalla query.

Cosa succede se aggiungiamo un ordinamento per colonna c , che non è in SELECT -list, vedremo una nuova colonna aggiunta all'elenco di destinazione e contrassegnata come resjunk:

regress=> SELECT a, b FROM test ORDER BY c;
LOG:  plan:
DETAIL:     {PLANNEDSTMT 
   :commandType 1 
   ....
   :planTree 
      {SORT 
      ....
      :targetlist (
         {TARGETENTRY 
         :expr 
            {VAR 
            :varno 65001 
            :varattno 1
            ...
            }
         :resno 1 
         :resname a 
         ...
         :resjunk false
         }
         {TARGETENTRY 
         :expr 
            {VAR 
            :varno 65001 
            :varattno 2 
            ...
            }
         :resno 2 
         :resname b 
         ....
         :resjunk false
         }
         {TARGETENTRY 
         :expr 
            {VAR 
            :varno 65001 
            :varattno 3 
            ...
            }
         :resno 3 
         :resname  
         ....
         :resjunk true
         }
      )
      :qual  
      :lefttree 
         {SEQSCAN 
         ...
         :targetlist (
            {TARGETENTRY 
            :expr 
               {VAR 
               :varno 1 
               :varattno 1 
               ...
               }
            :resno 1 
            ...
            :resjunk false
            }
            {TARGETENTRY 
            :expr 
               {VAR 
               :varno 1 
               :varattno 2 
               ...
               }
            :resno 2 
            ...
            :resjunk false
            }
            {TARGETENTRY 
            :expr 
               {VAR 
               :varno 1 
               :varattno 3 
               ...
               }
            :resno 3
            ...
            :resjunk true
            }
         )
         ....
      }
   :rtable (
      {RTE 
      :alias  
      :eref 
         {ALIAS 
         :aliasname test 
         :colnames ("a" "b" "c")
         }
      ....
      :selectedCols (b 9 10 11)
      :modifiedCols (b)
      }
   )
   ....
   }

per il piano di query:

                          QUERY PLAN                           
---------------------------------------------------------------
 Sort  (cost=135.34..140.19 rows=1940 width=12)
   Sort Key: c
   ->  Seq Scan on test  (cost=0.00..29.40 rows=1940 width=12)
(3 rows)

Quindi c è contrassegnato come resjunk perché è una chiave di ordinamento che non fa parte dell'output del piano finale.

Vedrai anche ctid contrassegnato resjunk in AGGIORNAMENTO e ELIMINA piani per ragioni simili:la parte letta del piano recupera le righe da modificare e i loro ID tupla; questi vengono inseriti in una MODIFYTABLE più esterna nodo del piano che aggiorna la riga per contrassegnarla come eliminata e, se si tratta di un aggiornamento, inserisce una nuova versione della riga.

La ricerca che ha portato a questi risultati ha ricevuto finanziamenti dal Settimo programma quadro dell'Unione europea (7° PQ/2007-2013) nell'ambito della convenzione di sovvenzione n° 318633