В момента се задълбочавам в анализатора на PostgreSQL, преписването на заявки и планирането на заявки, като част от работата по сигурността на ниво ред за проекта AXLE. Тъй като забелязах, че има страхотна документация за цялостната структура и поток, но не много за някои от детайлите, реших да започна да публикувам за някои от по-объркващите ъгли.
Ако не се интересувате от изходния код на PostgreSQL и неговата вътрешна работа, можете да спрете да четете сега.
изброяване
Днешната тема е терминът „resjunk“, който се отнася до resjunk атрибут на целевия списък. Ще видите този термин в целия плановик и пренаписване, обикновено като предполагаемо знание. Името не е особено полезно.
изхвърляне колоните са описани в src/backend/executor/execJunk.c , където има умерено подробен коментар. Това обаче всъщност не обяснява всеобхватните идеи.
Концепцията е, че понякога PostgreSQL трябва да следи информацията за всеки кортеж, която не е част от изхода на заявката. Може да е ключ за сортиране, който не е част от списъка за избор, междинен резултат от подзаявка, която се използва като филтър, след което се отхвърля, или може да е вътрешна колона като ctid която не е изложена на потребителите.
Възлите на плана имат целеви списъци – това са списъци на колоните, изведени от този възел на плана. За прост тест SELECT a, b FROM колоните a и b ще се появи в целевия списък на възела на index или seqscan план за заявката. Можете сами да наблюдавате това, като активирате записването на плана според следния изрязан изход:
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)
}
)
....
}
Това е подробният план за:
QUERY PLAN -------------------------------------------------------- Seq Scan on test (cost=0.00..29.40 rows=1940 width=8)
В него ще видите, че SELECT има два записа в целевия списък, по един за всяка колона. Нито resjunk тъй като и двете се извеждат от заявката.
Ами ако добавим сортиране по колона c , което не е в SELECT -list, ще видим нова колона, добавена към целевия списък и маркирана като препращане:
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)
}
)
....
}
за плана на заявката:
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)
Така че c е маркиран като отпаднала защото това е ключ за сортиране, който не е част от крайния изход на плана.
Ще видите също ctid с маркировка отпаднала в АКТУАЛИЗИРАНЕ и ИЗТРИВАНЕ планове по подобни причини – прочетената част на плана извлича редовете за модифициране и техните идентификатори на кортежи; те се изтеглят в най-външната МОДИФИКАЦИЯ възел на плана, който актуализира реда, за да го маркира като изтрит и, ако е актуализация, вмъква нова версия на реда.
Изследванията, довели до тези резултати, са получили финансиране от Седмата рамкова програма на Европейския съюз (FP7/2007-2013) по споразумение за отпускане на безвъзмездни средства № 318633