Obecnie zagłębiam się w parser PostgreSQL, narzędzie do ponownego pisania zapytań i planer zapytań w ramach prac nad bezpieczeństwem na poziomie wiersza dla projektu AXLE. Ponieważ zauważyłem, że istnieje świetna dokumentacja na temat ogólnej struktury i przepływu, ale niewiele szczegółów, pomyślałem, że zacznę publikować o niektórych bardziej mylących zakątkach.
Jeśli nie interesuje Cię kod źródłowy PostgreSQL i jego wewnętrzne działanie, możesz teraz przestać czytać.
odrzucić
Dzisiejszym tematem jest termin „resjunk”, który odnosi się do resjunk atrybut listy docelowej. Zobaczysz ten termin przez planistę i pisarza, zwykle jako założoną wiedzę. Nazwa nie jest zbyt pomocna.
odrzucić kolumny są opisane w src/backend/executor/execJunk.c , gdzie jest umiarkowanie szczegółowy komentarz. Jednak tak naprawdę nie wyjaśnia nadrzędnych idei.
Koncepcja jest to, że czasami PostgreSQL musi śledzić informacje o krotce, które nie są częścią wyniku zapytania. Może to być klucz sortowania, który nie jest częścią listy wyboru, wynik pośredni z podzapytania, który jest używany jako filtr, a następnie odrzucany, lub może to być kolumna wewnętrzna, taka jak ctid które nie są widoczne dla użytkowników.
Węzły planu mają listy docelowe — są to listy kolumn wyprowadzanych przez ten węzeł planu. Dla prostego testu SELECT a, b FROM kolumny a i b pojawi się na liście docelowej indeksu lub węzła planu seqscan dla zapytania. Możesz to zaobserwować samodzielnie, włączając rejestrowanie planu, zgodnie z następującymi przyciętymi danymi wyjściowymi:
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) } ) .... }
Oto szczegółowy plan:
QUERY PLAN -------------------------------------------------------- Seq Scan on test (cost=0.00..29.40 rows=1940 width=8)
W nim zobaczysz, że SELECT ma dwa wpisy na liście docelowej, po jednym dla każdej kolumny. Nie jest też odrzucany ponieważ oba są wyprowadzane przez zapytanie.
Co jeśli dodamy sortowanie według kolumny c , którego nie ma w SELECT -list, zobaczymy nową kolumnę dodaną do listy docelowej i oznaczoną jako 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) } ) .... }
dla planu zapytań:
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)
Więc c jest oznaczony jako odrzucony ponieważ jest to klucz sortowania, który nie jest częścią końcowego wyniku planu.
Zobaczysz także ctid oznaczony jako odrzucony w AKTUALIZACJI i USUŃ plany z podobnych powodów – czytana część planu pobiera wiersze do modyfikacji i ich identyfikatory krotek; są one wciągane do najbardziej zewnętrznego MODIFYTABLE węzeł planu, który aktualizuje wiersz, aby oznaczyć go jako usunięty, a jeśli jest to aktualizacja, wstawia nową wersję wiersza.
Badania prowadzące do tych wyników otrzymały finansowanie z Siódmego Programu Ramowego Unii Europejskiej (FP7/2007-2013) w ramach umowy o grant nr 318633