-- exercise both hashed and sorted implementations of UNION/INTERSECT/EXCEPT
set enable_hashagg toon;
explain (costs off) select count(*) from
( select unique1 from tenk1 unionselect fivethous from tenk1 ) ss; select count(*) from
( select unique1 from tenk1 unionselect fivethous from tenk1 ) ss;
explain (costs off) select count(*) from
( select unique1 from tenk1 intersect select fivethous from tenk1 ) ss; select count(*) from
( select unique1 from tenk1 intersect select fivethous from tenk1 ) ss;
-- this query will prefer a sorted setop unless we force it. set enable_indexscan to off;
explain (costs off) select unique1 from tenk1 except select unique2 from tenk1 where unique2 != 10; select unique1 from tenk1 except select unique2 from tenk1 where unique2 != 10;
reset enable_indexscan;
-- the hashed implementation is sensitive to child plans' tuple slot types explain (costs off) select * from int8_tbl intersect select q2, q1 from int8_tbl orderby1, 2; select * from int8_tbl intersect select q2, q1 from int8_tbl orderby1, 2; select q2, q1 from int8_tbl intersect select * from int8_tbl orderby1, 2;
set enable_hashagg to off;
explain (costs off) select count(*) from
( select unique1 from tenk1 unionselect fivethous from tenk1 ) ss; select count(*) from
( select unique1 from tenk1 unionselect fivethous from tenk1 ) ss;
explain (costs off) select count(*) from
( select unique1 from tenk1 intersect select fivethous from tenk1 ) ss; select count(*) from
( select unique1 from tenk1 intersect select fivethous from tenk1 ) ss;
explain (costs off) select unique1 from tenk1 except select unique2 from tenk1 where unique2 != 10; select unique1 from tenk1 except select unique2 from tenk1 where unique2 != 10;
explain (costs off) select f1 from int4_tbl unionall
(select unique1 from tenk1 unionselect unique2 from tenk1);
reset enable_hashagg;
-- non-hashable type set enable_hashagg toon;
explain (costs off) select x from (values ('11'::varbit), ('10'::varbit)) _(x) unionselect x from (values ('11'::varbit), ('10'::varbit)) _(x);
set enable_hashagg to off;
explain (costs off) select x from (values ('11'::varbit), ('10'::varbit)) _(x) unionselect x from (values ('11'::varbit), ('10'::varbit)) _(x);
reset enable_hashagg;
-- arrays set enable_hashagg toon;
explain (costs off) select x from (values (array[1, 2]), (array[1, 3])) _(x) unionselect x from (values (array[1, 2]), (array[1, 4])) _(x); select x from (values (array[1, 2]), (array[1, 3])) _(x) unionselect x from (values (array[1, 2]), (array[1, 4])) _(x); explain (costs off) select x from (values (array[1, 2]), (array[1, 3])) _(x) intersect select x from (values (array[1, 2]), (array[1, 4])) _(x); select x from (values (array[1, 2]), (array[1, 3])) _(x) intersect select x from (values (array[1, 2]), (array[1, 4])) _(x); explain (costs off) select x from (values (array[1, 2]), (array[1, 3])) _(x) except select x from (values (array[1, 2]), (array[1, 4])) _(x); select x from (values (array[1, 2]), (array[1, 3])) _(x) except select x from (values (array[1, 2]), (array[1, 4])) _(x);
-- non-hashable type explain (costs off) select x from (values (array['10'::varbit]), (array['11'::varbit])) _(x) unionselect x from (values (array['10'::varbit]), (array['01'::varbit])) _(x); select x from (values (array['10'::varbit]), (array['11'::varbit])) _(x) unionselect x from (values (array['10'::varbit]), (array['01'::varbit])) _(x);
set enable_hashagg to off;
explain (costs off) select x from (values (array[1, 2]), (array[1, 3])) _(x) unionselect x from (values (array[1, 2]), (array[1, 4])) _(x); select x from (values (array[1, 2]), (array[1, 3])) _(x) unionselect x from (values (array[1, 2]), (array[1, 4])) _(x); explain (costs off) select x from (values (array[1, 2]), (array[1, 3])) _(x) intersect select x from (values (array[1, 2]), (array[1, 4])) _(x); select x from (values (array[1, 2]), (array[1, 3])) _(x) intersect select x from (values (array[1, 2]), (array[1, 4])) _(x); explain (costs off) select x from (values (array[1, 2]), (array[1, 3])) _(x) except select x from (values (array[1, 2]), (array[1, 4])) _(x); select x from (values (array[1, 2]), (array[1, 3])) _(x) except select x from (values (array[1, 2]), (array[1, 4])) _(x);
reset enable_hashagg;
-- records set enable_hashagg toon;
explain (costs off) select x from (values (row(1, 2)), (row(1, 3))) _(x) unionselect x from (values (row(1, 2)), (row(1, 4))) _(x); select x from (values (row(1, 2)), (row(1, 3))) _(x) unionselect x from (values (row(1, 2)), (row(1, 4))) _(x); explain (costs off) select x from (values (row(1, 2)), (row(1, 3))) _(x) intersect select x from (values (row(1, 2)), (row(1, 4))) _(x); select x from (values (row(1, 2)), (row(1, 3))) _(x) intersect select x from (values (row(1, 2)), (row(1, 4))) _(x); explain (costs off) select x from (values (row(1, 2)), (row(1, 3))) _(x) except select x from (values (row(1, 2)), (row(1, 4))) _(x); select x from (values (row(1, 2)), (row(1, 3))) _(x) except select x from (values (row(1, 2)), (row(1, 4))) _(x);
-- non-hashable type
-- With an anonymous row type, the typcache does not report that the -- type is hashable. (Otherwise, this would fail at execution time.) explain (costs off) select x from (values (row('10'::varbit)), (row('11'::varbit))) _(x) unionselect x from (values (row('10'::varbit)), (row('01'::varbit))) _(x); select x from (values (row('10'::varbit)), (row('11'::varbit))) _(x) unionselect x from (values (row('10'::varbit)), (row('01'::varbit))) _(x);
-- With a defined row type, the typcache can inspect the type's fields -- for hashability. create type ct1 as (f1 varbit); explain (costs off) select x from (values (row('10'::varbit)::ct1), (row('11'::varbit)::ct1)) _(x) unionselect x from (values (row('10'::varbit)::ct1), (row('01'::varbit)::ct1)) _(x); select x from (values (row('10'::varbit)::ct1), (row('11'::varbit)::ct1)) _(x) unionselect x from (values (row('10'::varbit)::ct1), (row('01'::varbit)::ct1)) _(x); drop type ct1;
set enable_hashagg to off;
explain (costs off) select x from (values (row(1, 2)), (row(1, 3))) _(x) unionselect x from (values (row(1, 2)), (row(1, 4))) _(x); select x from (values (row(1, 2)), (row(1, 3))) _(x) unionselect x from (values (row(1, 2)), (row(1, 4))) _(x); explain (costs off) select x from (values (row(1, 2)), (row(1, 3))) _(x) intersect select x from (values (row(1, 2)), (row(1, 4))) _(x); select x from (values (row(1, 2)), (row(1, 3))) _(x) intersect select x from (values (row(1, 2)), (row(1, 4))) _(x); explain (costs off) select x from (values (row(1, 2)), (row(1, 3))) _(x) except select x from (values (row(1, 2)), (row(1, 4))) _(x); select x from (values (row(1, 2)), (row(1, 3))) _(x) except select x from (values (row(1, 2)), (row(1, 4))) _(x);
-- non-sortable type
-- Ensure we get a HashAggregate plan. Keep enable_hashagg=off to ensure -- there's no chance of a sort. explain (costs off) select'123'::xid unionselect'123'::xid;
reset enable_hashagg;
-- -- Mixed types --
SELECT f1 FROM float8_tbl INTERSECT SELECT f1 FROM int4_tbl ORDERBY1;
SELECT f1 FROM float8_tbl EXCEPT SELECT f1 FROM int4_tbl ORDERBY1;
-- -- Operator precedence and (((((extra))))) parentheses --
SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl UNIONALLSELECT q2 FROM int8_tbl ORDERBY1;
SELECT q1 FROM int8_tbl INTERSECT (((SELECT q2 FROM int8_tbl UNIONALLSELECT q2 FROM int8_tbl))) ORDERBY1;
(((SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl ORDERBY1))) UNIONALLSELECT q2 FROM int8_tbl;
SELECT q1 FROM int8_tbl UNIONALLSELECT q2 FROM int8_tbl EXCEPT SELECT q1 FROM int8_tbl ORDERBY1;
SELECT q1 FROM int8_tbl UNIONALL (((SELECT q2 FROM int8_tbl EXCEPT SELECT q1 FROM int8_tbl ORDERBY1)));
(((SELECT q1 FROM int8_tbl UNIONALLSELECT q2 FROM int8_tbl))) EXCEPT SELECT q1 FROM int8_tbl ORDERBY1;
-- -- Subqueries with ORDER BY & LIMIT clauses --
-- In this syntax, ORDER BY/LIMIT apply to the result of the EXCEPT SELECT q1,q2 FROM int8_tbl EXCEPT SELECT q2,q1 FROM int8_tbl ORDERBY q2,q1;
-- This should fail, because q2 isn't a name of an EXCEPT output column SELECT q1 FROM int8_tbl EXCEPT SELECT q2 FROM int8_tbl ORDERBY q2 LIMIT1;
-- But this should work: SELECT q1 FROM int8_tbl EXCEPT (((SELECT q2 FROM int8_tbl ORDERBY q2 LIMIT1))) ORDERBY1;
-- -- New syntaxes (7.1) permit new tests --
(((((select * from int8_tbl)))));
-- -- Check behavior with empty select list (allowed since 9.4) --
-- check hashed implementation set enable_hashagg = true; set enable_sort = false;
-- We've no way to check hashed UNION as the empty pathkeys in the Append are -- fine to make use of Unique, which is cheaper than HashAggregate and we've -- no means to disable Unique. explain (costs off) selectfrom generate_series(1,5) intersect selectfrom generate_series(1,3);
-- Try a variation of the above but with a CTE which contains a column, again -- with an empty final select list.
-- Ensure we get the expected 1 row with 0 columns with cte as materialized (select s from generate_series(1,5) s) selectfrom cte unionselectfrom cte;
-- Ensure we get the same result as the above. with cte asnot materialized (select s from generate_series(1,5) s) selectfrom cte unionselectfrom cte;
reset enable_hashagg;
reset enable_sort;
-- -- Check handling of a case with unknown constants. We don't guarantee -- an undecorated constant will work in all cases, but historically this -- usage has worked, so test we don't break it. --
SELECT a.f1 FROM (SELECT'test'AS f1 FROM varchar_tbl) a UNION SELECT b.f1 FROM (SELECT f1 FROM varchar_tbl) b ORDERBY1;
-- This should fail, but it should produce an error cursor SELECT'3.4'::numericUNIONSELECT'foo';
-- -- Test that expression-index constraints can be pushed down through -- UNION or UNION ALL --
CREATE TEMP TABLE t1 (a text, b text); CREATEINDEX t1_ab_idx on t1 ((a || b)); CREATE TEMP TABLE t2 (ab text primarykey); INSERTINTO t1 VALUES ('a', 'b'), ('x', 'y'); INSERTINTO t2 VALUES ('ab'), ('xy');
set enable_seqscan = off; set enable_indexscan = on; set enable_bitmapscan = off; set enable_sort = off;
explain (costs off) SELECT * FROM
(SELECT a || b AS ab FROM t1 UNIONALL SELECT * FROM t2) t WHERE ab = 'ab';
explain (costs off) SELECT * FROM
(SELECT a || b AS ab FROM t1 UNION SELECT * FROM t2) t WHERE ab = 'ab';
-- -- Test that ORDER BY for UNION ALL can be pushed down to inheritance -- children. --
explain (costs off) select event_id from (select event_id from events unionall select event_id from other_events) ss orderby event_id;
droptable events_child, events, other_events;
reset enable_indexonlyscan;
-- Test constraint exclusion of UNION ALL subqueries explain (costs off) SELECT * FROM
(SELECT1AS t, * FROM tenk1 a UNIONALL SELECT2AS t, * FROM tenk1 b) c WHERE t = 2;
-- Test that we push quals into UNION sub-selects only when it's safe explain (costs off) SELECT * FROM
(SELECT1AS t, 2AS x UNION SELECT2AS t, 4AS x) ss WHERE x < 4 ORDERBY x;
SELECT * FROM
(SELECT1AS t, 2AS x UNION SELECT2AS t, 4AS x) ss WHERE x < 4 ORDERBY x;
explain (costs off) SELECT * FROM
(SELECT1AS t, generate_series(1,10) AS x UNION SELECT2AS t, 4AS x) ss WHERE x < 4 ORDERBY x;
SELECT * FROM
(SELECT1AS t, generate_series(1,10) AS x UNION SELECT2AS t, 4AS x) ss WHERE x < 4 ORDERBY x;
explain (costs off) SELECT * FROM
(SELECT1AS t, (random()*3)::intAS x UNION SELECT2AS t, 4AS x) ss WHERE x > 3 ORDERBY x;
SELECT * FROM
(SELECT1AS t, (random()*3)::intAS x UNION SELECT2AS t, 4AS x) ss WHERE x > 3 ORDERBY x;
-- Test cases where the native ordering of a sub-select has more pathkeys -- than the outer query cares about explain (costs off) selectdistinct q1 from
(selectdistinct * from int8_tbl i81 unionall selectdistinct * from int8_tbl i82) ss where q2 = q2;
selectdistinct q1 from
(selectdistinct * from int8_tbl i81 unionall selectdistinct * from int8_tbl i82) ss where q2 = q2;
explain (costs off) selectdistinct q1 from
(selectdistinct * from int8_tbl i81 unionall selectdistinct * from int8_tbl i82) ss where -q1 = q2;
selectdistinct q1 from
(selectdistinct * from int8_tbl i81 unionall selectdistinct * from int8_tbl i82) ss where -q1 = q2;
-- Test proper handling of parameterized appendrel paths when the -- potential join qual is expensive create function expensivefunc(int) returns int
language plpgsql immutable strict cost 10000 as $$begin return $1; end$$;
create temp table t3 asselect generate_series(-1000,1000) as x; createindex t3i on t3 (expensivefunc(x)); analyze t3;
explain (costs off) select * from
(select * from t3 a unionallselect * from t3 b) ss join int4_tbl on f1 = expensivefunc(x); select * from
(select * from t3 a unionallselect * from t3 b) ss join int4_tbl on f1 = expensivefunc(x);
droptable t3; drop function expensivefunc(int);
-- Test handling of appendrel quals that const-simplify into an AND explain (costs off) select * from
(select *, 0as x from int8_tbl a unionall select *, 1as x from int8_tbl b) ss where (x = 0) or (q1 >= q2 and q1 <= q2); select * from
(select *, 0as x from int8_tbl a unionall select *, 1as x from int8_tbl b) ss where (x = 0) or (q1 >= q2 and q1 <= q2);
-- -- Test the planner's ability to produce cheap startup plans with Append nodes --
-- Ensure we get a Nested Loop join between tenk1 and tenk2 explain (costs off) select t1.unique1 from tenk1 t1 innerjoin tenk2 t2 on t1.tenthous = t2.tenthous and t2.thousand = 0 unionall
(values(1)) limit1;
-- Ensure there is no problem if cheapest_startup_path is NULL explain (costs off) select * from tenk1 t1 leftjoin lateral
(select t1.tenthous from tenk2 t2 unionall (values(1))) ontruelimit1;
-- Test handling of Vars with varno 0 in estimate_array_length explain (verbose, costs off) selectnull::int[] unionallselectnull::int[] unionallselectnull::bigint[];
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-09-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.