Jeg dykker ned i PostgreSQL-parseren, forespørgselsomskriveren og forespørgselsplanlæggeren i øjeblikket, som en del af arbejdet med række-niveau-sikkerhed for AXLE-projektet. Da jeg har bemærket, at der er en del god dokumentation om den overordnede struktur og flow, men ikke meget om nogle af detaljerne, tænkte jeg, at jeg ville begynde at skrive om nogle af de mere forvirrende hjørner.
Hvis du ikke er interesseret i PostgreSQL-kildekoden og dens indre funktioner, kan du stoppe med at læse nu.
resjunk
Dagens emne er udtrykket "resjunk", som refererer til resjunk målliste-attribut. Du vil se dette udtryk gennem planlæggeren og omskriveren, normalt som påtaget viden. Navnet er ikke særlig nyttigt.
resjunk kolonner er beskrevet i src/backend/executor/execJunk.c , hvor der er en moderat detaljeret kommentar. Det forklarer dog ikke rigtig de overordnede ideer.
konceptet er, at PostgreSQL nogle gange har brug for at holde styr på per-tuple information, der ikke er en del af forespørgselsoutputtet. Det kan være en sorteringsnøgle, der ikke er en del af udvalgslisten, et mellemresultat fra en underforespørgsel, der bruges som et filter og derefter kasseres, eller det kan være en intern kolonne som ctid der ikke er udsat for brugere.
Planknudepunkter har mållister - disse er lister over kolonnerne, der er outputtet af den planknude. For en simpel VÆLG a, b FRA test kolonnerne a og b vises i mållisten for indeks- eller seqscan-planknuden for forespørgslen. Du kan selv observere dette ved at aktivere planlogning ifølge følgende trimmede output:
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) } ) .... }
Det er den detaljerede plan for:
QUERY PLAN -------------------------------------------------------- Seq Scan on test (cost=0.00..29.40 rows=1940 width=8)
I den vil du se, at SELECT har to poster i mållisten, en for hver kolonne. Heller ikke resjunk da begge udlæses af forespørgslen.
Hvad hvis vi tilføjer en sortering efter kolonne c , som ikke er i SELECT -liste, vil vi se en ny kolonne tilføjet til mållisten og markeret som 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) } ) .... }
for forespørgselsplanen:
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)
Så c er markeret med resjunk fordi det er en sorteringsnøgle, der ikke er en del af det endelige planoutput.
Du vil også se ctid markeret resjunk i OPDATERING og SLET planer af lignende årsager – den læste del af planen henter de rækker, der skal ændres, og deres tuple-id'er; disse trækkes ind i den yderste ÆNDRINGSTABEL planknude, der opdaterer rækken for at markere den som slettet, og hvis det er en opdatering, indsætter en ny version af rækken.
Den forskning, der fører til disse resultater, har modtaget støtte fra EU's syvende rammeprogram (FP7/2007-2013) under tilskudsaftale nr. 318633