PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

PostgreSQL Mut:Was ist „Resjunk“?

Im Rahmen der Arbeit an der Sicherheit auf Zeilenebene für das AXLE-Projekt beschäftige ich mich derzeit mit dem PostgreSQL-Parser, dem Abfrageumschreiber und dem Abfrageplaner. Da ich festgestellt habe, dass es einige großartige Dokumentationen über die Gesamtstruktur und den Ablauf gibt, aber nicht viel über einige der Details, dachte ich, ich würde anfangen, über einige der verwirrenderen Ecken zu posten.

Wenn Sie sich nicht für den PostgreSQL-Quellcode und sein Innenleben interessieren, können Sie jetzt aufhören zu lesen.

Resjunk

Das heutige Thema ist der Begriff „Resjunk“, der sich auf Resjunk bezieht target-list-Attribut. Sie werden diesen Begriff im gesamten Planer und Rewriter sehen, normalerweise als angenommenes Wissen. Der Name ist nicht sehr hilfreich.

Resjunk Spalten sind in src/backend/executor/execJunk.c beschrieben , wo es einen mäßig detaillierten Kommentar gibt. Es erklärt jedoch nicht wirklich die übergeordneten Ideen.

Das Konzept ist, dass PostgreSQL manchmal Informationen pro Tupel nachverfolgen muss, die nicht Teil der Abfrageausgabe sind. Es kann sich um einen Sortierschlüssel handeln, der nicht Teil der Auswahlliste ist, ein Zwischenergebnis einer Unterabfrage, die als Filter verwendet und dann verworfen wird, oder es kann sich um eine interne Spalte wie ctid handeln die den Benutzern nicht angezeigt wird.

Planknoten haben Ziellisten – das sind Listen der Spalten, die von diesem Planknoten ausgegeben werden. Für einen einfachen SELECT a, b FROM test die Spalten a und b wird in der Zielliste des Index- oder Seqscan-Planknotens für die Abfrage angezeigt. Sie können dies selbst beobachten, indem Sie die Planprotokollierung gemäß der folgenden gekürzten Ausgabe aktivieren:

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)
      }
   )
   ....
   }

Das ist der detaillierte Plan für:

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

Darin sehen Sie, dass die SELECT hat zwei Einträge in der Zielliste, einen für jede Spalte. Beides ist kein Resjunk da beide von der Abfrage ausgegeben werden.

Was wäre, wenn wir eine Sortierung nach Spalte c hinzufügen würden? , die nicht im SELECT steht -list sehen wir eine neue Spalte, die der Zielliste hinzugefügt und als Resjunk markiert wurde:

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)
      }
   )
   ....
   }

für den Abfrageplan:

                          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)

Also c ist als Resjunk gekennzeichnet da es sich um einen Sortierschlüssel handelt, der nicht Teil der endgültigen Planausgabe ist.

Sie sehen auch ctid als Resjunk gekennzeichnet unter UPDATE und LÖSCHEN Pläne aus ähnlichen Gründen – der Leseteil des Plans ruft die zu ändernden Zeilen und ihre Tupel-IDs ab; diese werden in eine äußerste MODIFYTABLE gezogen plan-Knoten, der die Zeile aktualisiert, um sie als gelöscht zu markieren, und, falls es sich um eine Aktualisierung handelt, eine neue Version der Zeile einfügt.

Die zu diesen Ergebnissen führende Forschung wurde vom Siebten Rahmenprogramm der Europäischen Union (RP7/2007-2013) unter der Finanzhilfevereinbarung Nr. 318633 finanziert