sql >> Database >  >> RDS >> PostgreSQL

PostgreSQL-lef:wat is "resjunk"?

Ik verdiep me momenteel in de PostgreSQL-parser, query-rewriter en queryplanner, als onderdeel van het werk aan beveiliging op rijniveau voor het AXLE-project. Omdat ik heb gemerkt dat er geweldige documentatie is over de algehele structuur en stroom, maar niet veel over sommige details, dacht ik dat ik zou beginnen met posten over enkele van de meer verwarrende hoeken.

Als je niet geïnteresseerd bent in de PostgreSQL-broncode en zijn innerlijke werking, kun je nu stoppen met lezen.

rejunk

Het onderwerp van vandaag is de term "resjunk", die verwijst naar resjunk target-list attribuut. Je zult deze term overal in de planner en herschrijver tegenkomen, meestal als veronderstelde kennis. De naam is niet erg behulpzaam.

rejunk kolommen worden beschreven in src/backend/executor/execJunk.c , waar er een redelijk gedetailleerde opmerking is. Het verklaart echter niet echt de overkoepelende ideeën.

Het concept is dat PostgreSQL soms informatie per tuple moet bijhouden die geen deel uitmaakt van de uitvoer van de query. Het kan een sorteersleutel zijn die geen deel uitmaakt van de selectielijst, een tussenresultaat van een subquery die als filter wordt gebruikt en vervolgens wordt weggegooid, of het kan een interne kolom zijn zoals ctid die niet wordt blootgesteld aan gebruikers.

Planknooppunten hebben doellijsten - dit zijn lijsten met de kolommen die door dat planknooppunt worden uitgevoerd. Voor een eenvoudige SELECT a, b FROM test de kolommen a en b verschijnt in de doellijst van het index- of seqscan-planknooppunt voor de query. U kunt dit zelf waarnemen door planregistratie in te schakelen, volgens de volgende getrimde uitvoer:

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

Dat is het gedetailleerde plan voor:

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

Daarin zul je zien dat de SELECT heeft twee items in de doellijst, één voor elke kolom. Evenmin is resjunk aangezien beide worden uitgevoerd door de query.

Wat als we een sortering op kolom toevoegen c , die niet in de SELECT . staat -lijst, we zien een nieuwe kolom toegevoegd aan de doellijst en gemarkeerd als 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)
      }
   )
   ....
   }

voor het zoekplan:

                          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)

Dus c is gemarkeerd als resjunk omdat het een sorteersleutel is die geen deel uitmaakt van de uiteindelijke planuitvoer.

Je ziet ook ctid gemarkeerd als resjunk in UPDATE en VERWIJDEREN plannen om soortgelijke redenen - het leesgedeelte van het plan haalt de rijen op die moeten worden gewijzigd en hun tuple-ID's; deze worden in een buitenste MODIFYTABLE . getrokken plan-knooppunt dat de rij bijwerkt om deze als verwijderd te markeren en, als het een update is, een nieuwe versie van de rij invoegt.

Het onderzoek dat tot deze resultaten heeft geleid, heeft financiering ontvangen van het zevende kaderprogramma van de Europese Unie (FP7/2007-2013) onder subsidieovereenkomst nr. 318633


  1. Wacht-time-out voor vergrendeling overschreden; probeer de transactie opnieuw te starten, ook al gebruik ik geen transactie

  2. SQLite ALTER TABLE

  3. LDAP-verificatie en groepstoewijzing configureren met MariaDB

  4. Benchmarking Postgres-XL