Re: avoid bitmapOR-ing indexes with scan condition inconsistent with partition constraint - Mailing list pgsql-hackers
From | Tom Lane |
---|---|
Subject | Re: avoid bitmapOR-ing indexes with scan condition inconsistent with partition constraint |
Date | |
Msg-id | 228337.1605212074@sss.pgh.pa.us Whole thread Raw |
In response to | Re: avoid bitmapOR-ing indexes with scan condition inconsistent with partition constraint (Konstantin Knizhnik <knizhnik@garret.ru>) |
Responses |
Re: avoid bitmapOR-ing indexes with scan condition inconsistent with partition constraint
|
List | pgsql-hackers |
I started looking through this patch. I really quite dislike solving this via a kluge in indxpath.c. There are multiple disadvantages to that: * It only helps for the very specific problem of redundant bitmap index scans, whereas the problem of applying redundant qual checks in partition scans seems pretty general. * It's not unlikely that this will end up trying to make the same proof multiple times (and the lack of any way to turn that off, through constraint_exclusion or some other knob, isn't too cool). * It does nothing to fix rowcount estimates in the light of the knowledge that some of the restriction clauses are no-ops. Now, if we have up-to-date stats we'll probably manage to come out with an appropriate 0 or 1 selectivity anyway, but we might not have those. In any case, spending significant effort to estimate a selectivity when some other part of the code has taken the trouble to *prove* the clause true or false seems very undesirable. * I'm not even convinced that the logic is correct, specifically that it's okay to just "continue" if we refute the OR clause. That seems likely to break generate_bitmap_or_paths' surrounding loop logic about "We must be able to match at least one index to each of the arms of the OR". At least, if that still works it requires more than zero commentary about why. So I like much better the idea of Konstantin's old patch, that we modify the rel's baserestrictinfo list by removing quals that we can prove true. We could extend that to solve the bitmapscan problem by removing OR arms that we can prove false. So I started to review that patch more carefully, and after awhile realized that it has a really fundamental problem: it is trying to use CHECK predicates to prove WHERE clauses. But we don't know that CHECK predicates are true, only that they are not-false, and there is no proof mode in predtest.c that will allow proving some clauses true based only on other ones being not-false. We can salvage something by restricting the input quals to be only partition quals, since those are built to be guaranteed-true-or-false; we can assume they don't yield NULL. There's a hole in that for hashing, as I noted elsewhere, but we'll fail to prove anything anyway from a satisfies_hash_partition() qual. (In principle we could also use attnotnull quals, which also have that property. But I'm dubious that that will help often enough to be worth the extra cycles for predtest.c to process them.) So after a bit of coding I had the attached. This follows Konstantin's original patch in letting relation_excluded_by_constraints() change the baserestrictinfo list. I read the comments in the older thread about people not liking that, and I can see the point. But I'm not convinced that the later iterations of the patch were an improvement, because (a) the call locations for remove_restrictions_implied_by_constraints() seemed pretty random, and (b) it seems necessary to have relation_excluded_by_constraints() and remove_restrictions_implied_by_constraints() pretty much in bed with each other if we don't want to duplicate constraint-fetching work. Note the comment on get_relation_constraints() that it's called at most once per relation; that's not something I particularly desire to give up, because a relcache open isn't terribly cheap. Also (c) I think it's important that there be a way to suppress this overhead when it's not useful. In the patch as attached, turning off constraint_exclusion does that since relation_excluded_by_constraints() falls out before getting to the new code. If we make remove_restrictions_implied_by_constraints() independent then it will need some possibly-quite-duplicative logic to check constraint_exclusion. (Of course, if we'd rather condition this on some other GUC then that argument falls down. But I think we need something.) So, I'm not dead set on this code structure, but I haven't seen one I like better. Anyway, this seems to work, and if the regression test changes are any guide then it may fire often enough in the real world to be useful. Nonetheless, I'm concerned about performance, because predtest.c is a pretty expensive thing and there will be a lot of cases where the work is useless. I did a quick check using pgbench's option to partition the tables, and observed that the -S (select only) test case seemed to get about 2.5% slower with the patch than without. That's not far outside the noise floor, so maybe it's not real, but if it is real then it seems pretty disastrous. Perhaps we could avoid that problem by removing the "predicate_implied_by" cases and only trying the "predicate_refuted_by" case, so that no significant time is added unless you've got an OR restriction clause on a partitioned table. That seems like it'd lose a lot of the benefit though :-(. So I'm not sure where to go from here. Thoughts? Anyone else care to run some performance tests? regards, tom lane diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index 2d88d06358..01151cef8d 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -7836,18 +7836,17 @@ insert into utrtest values (2, 'qux'); -- Check case where the foreign partition is a subplan target rel explain (verbose, costs off) update utrtest set a = 1 where a = 1 or a = 2 returning *; - QUERY PLAN ----------------------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------- Update on public.utrtest Output: utrtest_1.a, utrtest_1.b Foreign Update on public.remp utrtest_1 Update on public.locp utrtest_2 -> Foreign Update on public.remp utrtest_1 - Remote SQL: UPDATE public.loct SET a = 1 WHERE (((a = 1) OR (a = 2))) RETURNING a, b + Remote SQL: UPDATE public.loct SET a = 1 RETURNING a, b -> Seq Scan on public.locp utrtest_2 Output: 1, utrtest_2.b, utrtest_2.ctid - Filter: ((utrtest_2.a = 1) OR (utrtest_2.a = 2)) -(9 rows) +(8 rows) -- The new values are concatenated with ' triggered !' update utrtest set a = 1 where a = 1 or a = 2 returning *; @@ -7868,8 +7867,7 @@ update utrtest set a = 1 where a = 2 returning *; Update on public.locp utrtest_1 -> Seq Scan on public.locp utrtest_1 Output: 1, utrtest_1.b, utrtest_1.ctid - Filter: (utrtest_1.a = 2) -(6 rows) +(5 rows) -- The new values are concatenated with ' triggered !' update utrtest set a = 1 where a = 2 returning *; diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 52c01eb86b..15c50b9522 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -35,12 +35,14 @@ #include "foreign/fdwapi.h" #include "miscadmin.h" #include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" #include "nodes/supportnodes.h" #include "optimizer/clauses.h" #include "optimizer/cost.h" #include "optimizer/optimizer.h" #include "optimizer/plancat.h" #include "optimizer/prep.h" +#include "optimizer/restrictinfo.h" #include "parser/parse_relation.h" #include "parser/parsetree.h" #include "partitioning/partdesc.h" @@ -70,6 +72,8 @@ static List *get_relation_constraints(PlannerInfo *root, bool include_noinherit, bool include_notnull, bool include_partition); +static void remove_restrictions_implied_by_constraints(RelOptInfo *rel, + List *given_clauses); static List *build_index_tlist(PlannerInfo *root, IndexOptInfo *index, Relation heapRelation); static List *get_relation_statistics(RelOptInfo *rel, Relation relation); @@ -1276,13 +1280,16 @@ get_relation_constraints(PlannerInfo *root, } /* - * Add partitioning constraints, if requested. + * If the table is a partition, make sure we have the partition qual, and + * add it to the result if requested. (But even if it's not requested, + * fetch it while we have the relcache entry open.) */ - if (include_partition && relation->rd_rel->relispartition) + if (relation->rd_rel->relispartition) { /* make sure rel->partition_qual is set */ set_baserel_partition_constraint(relation, rel); - result = list_concat(result, rel->partition_qual); + if (include_partition) + result = list_concat(result, rel->partition_qual); } table_close(relation, NoLock); @@ -1387,6 +1394,14 @@ get_relation_statistics(RelOptInfo *rel, Relation relation) * self-inconsistent restrictions, or restrictions inconsistent with the * relation's applicable constraints. * + * Even if the relation does need to be scanned, we may be able to remove + * or simplify some of its baserestrictinfo clauses on the basis that + * they can be proven true, or some OR arms can be proven false, using + * the relation's applicable constraints. Hence, this function may also + * update rel->baserestrictinfo. (It's a bit hackish to include that in + * this function's responsibilities, but it saves fetching the constraint + * expressions twice.) + * * Note: this examines only rel->relid, rel->reloptkind, and * rel->baserestrictinfo; therefore it can be called before filling in * other fields of the RelOptInfo. @@ -1562,9 +1577,171 @@ relation_excluded_by_constraints(PlannerInfo *root, if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo, false)) return true; + /* + * OK, we do need to scan the relation, but we might be able to simplify + * its baserestrictinfo list. For this purpose, we may use its partition + * constraint even if that was deemed duplicative above. + * (get_relation_constraints() will have set rel->partition_qual for us.) + * + * Unfortunately, we *cannot* use regular CHECK constraints here, because + * we can only assume that those are not-FALSE, not that they are surely + * TRUE. (Partitioning constraints are constructed to be either TRUE or + * FALSE, so we can make the needed proofs with them.) We could use + * attnotnull constraints, but it's not clear that those would add enough + * to be worth another relcache visit. + */ + if (rel->partition_qual) + remove_restrictions_implied_by_constraints(rel, rel->partition_qual); + return false; } +/* + * Remove or simplify any rel->baserestrictinfo clauses that are implied + * or refuted by the given_clauses. Note that we assume the given + * clauses are known TRUE, not just that they are known not-FALSE. + */ +static void +remove_restrictions_implied_by_constraints(RelOptInfo *rel, + List *given_clauses) +{ + List *new_restrictions = NIL; + ListCell *lc; + + foreach(lc, rel->baserestrictinfo) + { + RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc); + + if (!restriction_is_or_clause(rinfo)) + { + /* + * Simple clause: see if we can prove it redundant. There's no + * need to try to refute it though; we should not have got here if + * that were possible. Note: predicate_implied_by expects us to + * verify that its first argument contains no volatile functions. + */ + if (contain_mutable_functions((Node *) rinfo->clause) || + !predicate_implied_by(list_make1(rinfo->clause), + given_clauses, + false)) + new_restrictions = lappend(new_restrictions, rinfo); + } + else + { + /* + * OR clause: try to prove or refute each OR arm individually. + * Refuted arms can be dropped. If we prove any one arm true, the + * whole OR is true and can be dropped in toto. + */ + List *or_args = ((BoolExpr *) rinfo->clause)->args; + List *new_or_args = NIL; + bool or_is_true = false; + ListCell *lc2; + + foreach(lc2, or_args) + { + Node *orarg = (Node *) lfirst(lc2); + + if (contain_mutable_functions(orarg)) + { + /* mutable, so no proof possible */ + new_or_args = lappend(new_or_args, orarg); + } + else if (predicate_implied_by(list_make1(orarg), + given_clauses, + false)) + { + /* orarg is provably true, therefore the OR is as well */ + or_is_true = true; + break; + } + else if (predicate_refuted_by(list_make1(orarg), + given_clauses, + true)) + { + /* orarg is provably false-or-null, drop it */ + continue; + } + else + new_or_args = lappend(new_or_args, orarg); + } + + /* Drop constant-true OR clauses from baserestrictinfo */ + if (or_is_true) + continue; + + if (list_length(new_or_args) == list_length(or_args)) + { + /* Needn't rebuild the RestrictInfo if we eliminated nothing */ + new_restrictions = lappend(new_restrictions, rinfo); + } + else if (new_or_args == NIL) + { + /* + * Hmm, we refuted all the arms, making the OR constant-false. + * This case should be unreachable, because if this is + * provable then relation_excluded_by_constraints should have + * excluded the rel altogether. Hence, don't work hard here; + * if we do somehow get here, just re-use the RestrictInfo. + */ + new_restrictions = lappend(new_restrictions, rinfo); + } + else + { + /* Otherwise, build RestrictInfo(s) from the surviving arms */ + Expr *newclause; + RestrictInfo *newrinfo; + + /* Build valid clause, with OR only if needed */ + if (list_length(new_or_args) == 1) + newclause = (Expr *) linitial(new_or_args); + else + newclause = make_orclause(new_or_args); + + if (is_andclause(newclause)) + { + /* + * We must manually flatten this AND-below-OR, now that + * we've removed all its sibling OR arms. In principle, + * we could now try to prune these clauses individually, + * but it doesn't seem likely to be worth the effort. + */ + ListCell *lc3; + + foreach(lc3, ((BoolExpr *) newclause)->args) + { + Expr *andarm = (Expr *) lfirst(lc3); + + newrinfo = make_restrictinfo(andarm, + rinfo->is_pushed_down, + rinfo->outerjoin_delayed, + false, + rinfo->security_level, + NULL, + rinfo->outer_relids, + rinfo->nullable_relids); + new_restrictions = lappend(new_restrictions, newrinfo); + } + } + else + { + newrinfo = make_restrictinfo(newclause, + rinfo->is_pushed_down, + rinfo->outerjoin_delayed, + false, + rinfo->security_level, + NULL, + rinfo->outer_relids, + rinfo->nullable_relids); + new_restrictions = lappend(new_restrictions, newrinfo); + } + } + } + } + + rel->baserestrictinfo = new_restrictions; +} + /* * build_physical_tlist diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index ed8c01b8de..0c9be92af6 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -529,11 +529,10 @@ create table partitioned2 partition of partitioned for values in ('(2,4)'::partitioned); explain (costs off) select * from partitioned where row(a,b)::partitioned = '(1,2)'::partitioned; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +-------------------------------------- Seq Scan on partitioned1 partitioned - Filter: (ROW(a, b)::partitioned = '(1,2)'::partitioned) -(2 rows) +(1 row) drop table partitioned; -- whole-row Var in partition key works too @@ -545,11 +544,10 @@ create table partitioned2 partition of partitioned for values in ('(2,4)'); explain (costs off) select * from partitioned where partitioned = '(1,2)'::partitioned; - QUERY PLAN ------------------------------------------------------------------ + QUERY PLAN +-------------------------------------- Seq Scan on partitioned1 partitioned - Filter: ((partitioned.*)::partitioned = '(1,2)'::partitioned) -(2 rows) +(1 row) \d+ partitioned1 Table "public.partitioned1" diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index 2b68aef654..25eafe12c1 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -1800,22 +1800,19 @@ explain (costs off) select * from list_parted where a is not null; ---------------------------------------------- Append -> Seq Scan on part_ab_cd list_parted_1 - Filter: (a IS NOT NULL) -> Seq Scan on part_ef_gh list_parted_2 - Filter: (a IS NOT NULL) -> Seq Scan on part_null_xy list_parted_3 Filter: (a IS NOT NULL) -(7 rows) +(5 rows) explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef'); QUERY PLAN ---------------------------------------------------------- Append -> Seq Scan on part_ab_cd list_parted_1 - Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[])) -> Seq Scan on part_ef_gh list_parted_2 Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[])) -(5 rows) +(4 rows) explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd'); QUERY PLAN @@ -1878,26 +1875,21 @@ explain (costs off) select * from range_list_parted where b = 'ab'; ------------------------------------------------------ Append -> Seq Scan on part_1_10_ab range_list_parted_1 - Filter: (b = 'ab'::bpchar) -> Seq Scan on part_10_20_ab range_list_parted_2 - Filter: (b = 'ab'::bpchar) -> Seq Scan on part_21_30_ab range_list_parted_3 - Filter: (b = 'ab'::bpchar) -> Seq Scan on part_40_inf_ab range_list_parted_4 - Filter: (b = 'ab'::bpchar) -(9 rows) +(5 rows) explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab'); - QUERY PLAN ------------------------------------------------------------------ + QUERY PLAN +----------------------------------------------------- Append -> Seq Scan on part_1_10_ab range_list_parted_1 - Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) + Filter: (a >= 3) -> Seq Scan on part_10_20_ab range_list_parted_2 - Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) -> Seq Scan on part_21_30_ab range_list_parted_3 - Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar)) -(7 rows) + Filter: (a <= 23) +(6 rows) /* Should select no rows because range partition key cannot be null */ explain (costs off) select * from range_list_parted where a is null; @@ -1912,44 +1904,34 @@ explain (costs off) select * from range_list_parted where b is null; QUERY PLAN ------------------------------------------------ Seq Scan on part_40_inf_null range_list_parted - Filter: (b IS NULL) -(2 rows) +(1 row) explain (costs off) select * from range_list_parted where a is not null and a < 67; QUERY PLAN -------------------------------------------------------- Append -> Seq Scan on part_1_10_ab range_list_parted_1 - Filter: ((a IS NOT NULL) AND (a < 67)) -> Seq Scan on part_1_10_cd range_list_parted_2 - Filter: ((a IS NOT NULL) AND (a < 67)) -> Seq Scan on part_10_20_ab range_list_parted_3 - Filter: ((a IS NOT NULL) AND (a < 67)) -> Seq Scan on part_10_20_cd range_list_parted_4 - Filter: ((a IS NOT NULL) AND (a < 67)) -> Seq Scan on part_21_30_ab range_list_parted_5 - Filter: ((a IS NOT NULL) AND (a < 67)) -> Seq Scan on part_21_30_cd range_list_parted_6 - Filter: ((a IS NOT NULL) AND (a < 67)) -> Seq Scan on part_40_inf_ab range_list_parted_7 - Filter: ((a IS NOT NULL) AND (a < 67)) + Filter: (a < 67) -> Seq Scan on part_40_inf_cd range_list_parted_8 - Filter: ((a IS NOT NULL) AND (a < 67)) + Filter: (a < 67) -> Seq Scan on part_40_inf_null range_list_parted_9 - Filter: ((a IS NOT NULL) AND (a < 67)) -(19 rows) + Filter: (a < 67) +(13 rows) explain (costs off) select * from range_list_parted where a >= 30; QUERY PLAN -------------------------------------------------------- Append -> Seq Scan on part_40_inf_ab range_list_parted_1 - Filter: (a >= 30) -> Seq Scan on part_40_inf_cd range_list_parted_2 - Filter: (a >= 30) -> Seq Scan on part_40_inf_null range_list_parted_3 - Filter: (a >= 30) -(7 rows) +(4 rows) drop table list_parted; drop table range_list_parted; @@ -1990,7 +1972,7 @@ explain (costs off) select * from mcrparted where a = 10 and abs(b) = 5; -- scan -> Seq Scan on mcrparted1 mcrparted_1 Filter: ((a = 10) AND (abs(b) = 5)) -> Seq Scan on mcrparted2 mcrparted_2 - Filter: ((a = 10) AND (abs(b) = 5)) + Filter: (abs(b) = 5) -> Seq Scan on mcrparted_def mcrparted_3 Filter: ((a = 10) AND (abs(b) = 5)) (7 rows) @@ -2022,24 +2004,19 @@ explain (costs off) select * from mcrparted where a > -1; -- scans all partition -> Seq Scan on mcrparted0 mcrparted_1 Filter: (a > '-1'::integer) -> Seq Scan on mcrparted1 mcrparted_2 - Filter: (a > '-1'::integer) -> Seq Scan on mcrparted2 mcrparted_3 - Filter: (a > '-1'::integer) -> Seq Scan on mcrparted3 mcrparted_4 - Filter: (a > '-1'::integer) -> Seq Scan on mcrparted4 mcrparted_5 - Filter: (a > '-1'::integer) -> Seq Scan on mcrparted5 mcrparted_6 - Filter: (a > '-1'::integer) -> Seq Scan on mcrparted_def mcrparted_7 Filter: (a > '-1'::integer) -(15 rows) +(10 rows) explain (costs off) select * from mcrparted where a = 20 and abs(b) = 10 and c > 10; -- scans mcrparted4 - QUERY PLAN ------------------------------------------------------ + QUERY PLAN +---------------------------------------- Seq Scan on mcrparted4 mcrparted - Filter: ((c > 10) AND (a = 20) AND (abs(b) = 10)) + Filter: ((c > 10) AND (abs(b) = 10)) (2 rows) explain (costs off) select * from mcrparted where a = 20 and c > 20; -- scans mcrparted3, mcrparte4, mcrparte5, mcrparted_def @@ -2049,7 +2026,7 @@ explain (costs off) select * from mcrparted where a = 20 and c > 20; -- scans mc -> Seq Scan on mcrparted3 mcrparted_1 Filter: ((c > 20) AND (a = 20)) -> Seq Scan on mcrparted4 mcrparted_2 - Filter: ((c > 20) AND (a = 20)) + Filter: (c > 20) -> Seq Scan on mcrparted5 mcrparted_3 Filter: ((c > 20) AND (a = 20)) -> Seq Scan on mcrparted_def mcrparted_4 @@ -2069,11 +2046,11 @@ explain (costs off) select min(a), max(a) from parted_minmax where b = '12345'; InitPlan 1 (returns $0) -> Limit -> Index Only Scan using parted_minmax1i on parted_minmax1 parted_minmax - Index Cond: ((a IS NOT NULL) AND (b = '12345'::text)) + Index Cond: (b = '12345'::text) InitPlan 2 (returns $1) -> Limit -> Index Only Scan Backward using parted_minmax1i on parted_minmax1 parted_minmax_1 - Index Cond: ((a IS NOT NULL) AND (b = '12345'::text)) + Index Cond: (b = '12345'::text) (9 rows) select min(a), max(a) from parted_minmax where b = '12345'; @@ -2173,14 +2150,11 @@ explain (costs off) select * from mcrparted where a < 20 order by a, abs(b), c; ------------------------------------------------------------------------- Append -> Index Scan using mcrparted0_a_abs_c_idx on mcrparted0 mcrparted_1 - Index Cond: (a < 20) -> Index Scan using mcrparted1_a_abs_c_idx on mcrparted1 mcrparted_2 - Index Cond: (a < 20) -> Index Scan using mcrparted2_a_abs_c_idx on mcrparted2 mcrparted_3 - Index Cond: (a < 20) -> Index Scan using mcrparted3_a_abs_c_idx on mcrparted3 mcrparted_4 Index Cond: (a < 20) -(9 rows) +(6 rows) create table mclparted (a int) partition by list(a); create table mclparted1 partition of mclparted for values in(1); @@ -2226,14 +2200,11 @@ explain (costs off) select * from mcrparted where a < 20 order by a, abs(b), c l -> Sort Sort Key: mcrparted_1.a, (abs(mcrparted_1.b)), mcrparted_1.c -> Seq Scan on mcrparted0 mcrparted_1 - Filter: (a < 20) -> Index Scan using mcrparted1_a_abs_c_idx on mcrparted1 mcrparted_2 - Index Cond: (a < 20) -> Index Scan using mcrparted2_a_abs_c_idx on mcrparted2 mcrparted_3 - Index Cond: (a < 20) -> Index Scan using mcrparted3_a_abs_c_idx on mcrparted3 mcrparted_4 Index Cond: (a < 20) -(12 rows) +(9 rows) set enable_bitmapscan = 0; -- Ensure Append node can be used when the partition is ordered by some @@ -2245,8 +2216,7 @@ explain (costs off) select * from mcrparted where a = 10 order by a, abs(b), c; -> Index Scan using mcrparted1_a_abs_c_idx on mcrparted1 mcrparted_1 Index Cond: (a = 10) -> Index Scan using mcrparted2_a_abs_c_idx on mcrparted2 mcrparted_2 - Index Cond: (a = 10) -(5 rows) +(4 rows) reset enable_bitmapscan; drop table mcrparted; @@ -2276,39 +2246,35 @@ explain (costs off) select * from bool_rp where b = true order by b,a; ---------------------------------------------------------------------------------- Append -> Index Only Scan using bool_rp_true_1k_b_a_idx on bool_rp_true_1k bool_rp_1 - Index Cond: (b = true) -> Index Only Scan using bool_rp_true_2k_b_a_idx on bool_rp_true_2k bool_rp_2 - Index Cond: (b = true) -(5 rows) +(3 rows) explain (costs off) select * from bool_rp where b = false order by b,a; QUERY PLAN ------------------------------------------------------------------------------------ Append -> Index Only Scan using bool_rp_false_1k_b_a_idx on bool_rp_false_1k bool_rp_1 - Index Cond: (b = false) -> Index Only Scan using bool_rp_false_2k_b_a_idx on bool_rp_false_2k bool_rp_2 - Index Cond: (b = false) -(5 rows) +(3 rows) explain (costs off) select * from bool_rp where b = true order by a; - QUERY PLAN ----------------------------------------------------------------------------------- - Append - -> Index Only Scan using bool_rp_true_1k_b_a_idx on bool_rp_true_1k bool_rp_1 - Index Cond: (b = true) - -> Index Only Scan using bool_rp_true_2k_b_a_idx on bool_rp_true_2k bool_rp_2 - Index Cond: (b = true) + QUERY PLAN +--------------------------------------------------- + Sort + Sort Key: bool_rp.a + -> Append + -> Seq Scan on bool_rp_true_1k bool_rp_1 + -> Seq Scan on bool_rp_true_2k bool_rp_2 (5 rows) explain (costs off) select * from bool_rp where b = false order by a; - QUERY PLAN ------------------------------------------------------------------------------------- - Append - -> Index Only Scan using bool_rp_false_1k_b_a_idx on bool_rp_false_1k bool_rp_1 - Index Cond: (b = false) - -> Index Only Scan using bool_rp_false_2k_b_a_idx on bool_rp_false_2k bool_rp_2 - Index Cond: (b = false) + QUERY PLAN +---------------------------------------------------- + Sort + Sort Key: bool_rp.a + -> Append + -> Seq Scan on bool_rp_false_1k bool_rp_1 + -> Seq Scan on bool_rp_false_2k bool_rp_2 (5 rows) drop table bool_rp; diff --git a/src/test/regress/expected/partition_aggregate.out b/src/test/regress/expected/partition_aggregate.out index 45c698daf4..ebfdf15fb0 100644 --- a/src/test/regress/expected/partition_aggregate.out +++ b/src/test/regress/expected/partition_aggregate.out @@ -738,16 +738,13 @@ SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a LEFT JOI Filter: ((pagg_tab1.x > 5) OR (pagg_tab2.y < 20)) -> Append -> Seq Scan on pagg_tab1_p1 pagg_tab1_1 - Filter: (x < 20) -> Seq Scan on pagg_tab1_p2 pagg_tab1_2 - Filter: (x < 20) -> Hash -> Append -> Seq Scan on pagg_tab2_p2 pagg_tab2_1 Filter: (y > 10) -> Seq Scan on pagg_tab2_p3 pagg_tab2_2 - Filter: (y > 10) -(18 rows) +(15 rows) SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a LEFT JOIN (SELECT * FROM pagg_tab2 WHERE y > 10)b ON a.x = b.y WHERE a.x > 5 or b.y < 20 GROUP BY a.x, b.y ORDER BY 1, 2; x | y | count @@ -778,16 +775,13 @@ SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a FULL JOI Filter: ((pagg_tab1.x > 5) OR (pagg_tab2.y < 20)) -> Append -> Seq Scan on pagg_tab1_p1 pagg_tab1_1 - Filter: (x < 20) -> Seq Scan on pagg_tab1_p2 pagg_tab1_2 - Filter: (x < 20) -> Hash -> Append -> Seq Scan on pagg_tab2_p2 pagg_tab2_1 Filter: (y > 10) -> Seq Scan on pagg_tab2_p3 pagg_tab2_2 - Filter: (y > 10) -(18 rows) +(15 rows) SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a FULL JOIN (SELECT * FROM pagg_tab2 WHERE y > 10)b ON a.x = b.y WHERE a.x > 5 or b.y < 20 GROUP BY a.x, b.y ORDER BY 1, 2; x | y | count diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out index 0057f41caa..2c748aa780 100644 --- a/src/test/regress/expected/partition_join.out +++ b/src/test/regress/expected/partition_join.out @@ -218,14 +218,13 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JO -> Seq Scan on prt2_p2 prt2_1 Filter: (b > 250) -> Seq Scan on prt2_p3 prt2_2 - Filter: (b > 250) -> Hash -> Append -> Seq Scan on prt1_p1 prt1_1 - Filter: ((a < 450) AND (b = 0)) + Filter: (b = 0) -> Seq Scan on prt1_p2 prt1_2 Filter: ((a < 450) AND (b = 0)) -(15 rows) +(14 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * FROM prt2 WHERE b > 250) t2ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b; a | c | b | c @@ -253,7 +252,6 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 FULL JO Filter: ((prt1.b = 0) OR (prt2.a = 0)) -> Append -> Seq Scan on prt1_p1 prt1_1 - Filter: (a < 450) -> Seq Scan on prt1_p2 prt1_2 Filter: (a < 450) -> Hash @@ -261,8 +259,7 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 FULL JO -> Seq Scan on prt2_p2 prt2_1 Filter: (b > 250) -> Seq Scan on prt2_p3 prt2_2 - Filter: (b > 250) -(16 rows) +(14 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a < 450) t1 FULL JOIN (SELECT * FROM prt2 WHERE b > 250) t2ON t1.a = t2.b WHERE t1.b = 0 OR t2.a = 0 ORDER BY t1.a, t2.b; a | c | b | c @@ -1181,7 +1178,7 @@ SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * Sort Key: prt1.a -> Append -> Seq Scan on prt1_p1 prt1_1 - Filter: ((a < 450) AND (b = 0)) + Filter: (b = 0) -> Seq Scan on prt1_p2 prt1_2 Filter: ((a < 450) AND (b = 0)) -> Sort @@ -1190,8 +1187,7 @@ SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * -> Seq Scan on prt2_p2 prt2_1 Filter: (b > 250) -> Seq Scan on prt2_p3 prt2_2 - Filter: (b > 250) -(18 rows) +(17 rows) SELECT t1.a, t2.b FROM (SELECT * FROM prt1 WHERE a < 450) t1 LEFT JOIN (SELECT * FROM prt2 WHERE b > 250) t2 ON t1.a = t2.bWHERE t1.b = 0 ORDER BY t1.a, t2.b; a | b @@ -2197,7 +2193,7 @@ where not exists (select 1 from prtx2 Append -> Nested Loop Anti Join -> Seq Scan on prtx1_1 - Filter: ((a < 20) AND (c = 120)) + Filter: (c = 120) -> Bitmap Heap Scan on prtx2_1 Recheck Cond: ((b = prtx1_1.b) AND (c = 123)) Filter: (a = prtx1_1.a) @@ -2238,7 +2234,7 @@ where not exists (select 1 from prtx2 Append -> Nested Loop Anti Join -> Seq Scan on prtx1_1 - Filter: ((a < 20) AND (c = 91)) + Filter: (c = 91) -> Bitmap Heap Scan on prtx2_1 Recheck Cond: ((b = (prtx1_1.b + 1)) OR (c = 99)) Filter: (a = prtx1_1.a) @@ -3102,8 +3098,8 @@ INSERT INTO prt2_adv SELECT i % 25, i, to_char(i, 'FM0000') FROM generate_series ANALYZE prt2_adv; EXPLAIN (COSTS OFF) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.a < 300 AND t1.b = 0 ORDERBY t1.a, t2.b; - QUERY PLAN ------------------------------------------------------------ + QUERY PLAN +------------------------------------------------------ Sort Sort Key: t1.a -> Append @@ -3112,13 +3108,13 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = -> Seq Scan on prt2_adv_p1 t2_1 -> Hash -> Seq Scan on prt1_adv_p1 t1_1 - Filter: ((a < 300) AND (b = 0)) + Filter: (b = 0) -> Hash Join Hash Cond: (t2_2.b = t1_2.a) -> Seq Scan on prt2_adv_p2 t2_2 -> Hash -> Seq Scan on prt1_adv_p2 t1_2 - Filter: ((a < 300) AND (b = 0)) + Filter: (b = 0) (15 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.a < 300 AND t1.b = 0 ORDERBY t1.a, t2.b; @@ -3141,8 +3137,8 @@ CREATE TABLE prt2_adv_default PARTITION OF prt2_adv DEFAULT; ANALYZE prt2_adv; EXPLAIN (COSTS OFF) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.a >= 100 AND t1.a < 300AND t1.b = 0 ORDER BY t1.a, t2.b; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------ Sort Sort Key: t1.a -> Append @@ -3151,13 +3147,13 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = -> Seq Scan on prt2_adv_p1 t2_1 -> Hash -> Seq Scan on prt1_adv_p1 t1_1 - Filter: ((a >= 100) AND (a < 300) AND (b = 0)) + Filter: (b = 0) -> Hash Join Hash Cond: (t2_2.b = t1_2.a) -> Seq Scan on prt2_adv_p2 t2_2 -> Hash -> Seq Scan on prt1_adv_p2 t1_2 - Filter: ((a >= 100) AND (a < 300) AND (b = 0)) + Filter: (b = 0) (15 rows) SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.a >= 100 AND t1.a < 300AND t1.b = 0 ORDER BY t1.a, t2.b; @@ -4456,7 +4452,7 @@ SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = -> Seq Scan on plt2_adv_p3 t2_1 -> Hash -> Seq Scan on plt1_adv_p3 t1_1 - Filter: ((b < 10) AND (c = ANY ('{0003,0004,0005}'::text[]))) + Filter: (b < 10) -> Hash Join Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c)) -> Seq Scan on plt2_adv_p4 t2_2 @@ -4509,7 +4505,7 @@ SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = -> Seq Scan on plt2_adv_p3 t2_1 -> Hash -> Seq Scan on plt1_adv_p3 t1_1 - Filter: ((b < 10) AND (c = ANY ('{0003,0004,0005}'::text[]))) + Filter: (b < 10) -> Hash Join Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c)) -> Seq Scan on plt2_adv_p4 t2_2 @@ -4699,7 +4695,7 @@ SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.b = t2 -> Hash Join Hash Cond: ((t1_1.a = t2_1.a) AND (t1_1.b = t2_1.b)) -> Seq Scan on alpha_neg_p1 t1_1 - Filter: ((b >= 125) AND (b < 225)) + Filter: (b >= 125) -> Hash -> Seq Scan on beta_neg_p1 t2_1 -> Hash Join @@ -4707,7 +4703,7 @@ SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.b = t2 -> Seq Scan on beta_neg_p2 t2_2 -> Hash -> Seq Scan on alpha_neg_p2 t1_2 - Filter: ((b >= 125) AND (b < 225)) + Filter: (b < 225) -> Hash Join Hash Cond: ((t2_4.a = t1_4.a) AND (t2_4.b = t1_4.b)) -> Append @@ -4771,8 +4767,8 @@ SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.b = t2 EXPLAIN (COSTS OFF) SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.c = t2.c) WHERE ((t1.b >= 100 AND t1.b < 110)OR (t1.b >= 200 AND t1.b < 210)) AND ((t2.b >= 100 AND t2.b < 110) OR (t2.b >= 200 AND t2.b < 210)) AND t1.c IN ('0004','0009') ORDER BY t1.a, t1.b, t2.b; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------- Sort Sort Key: t1.a, t1.b, t2.b -> Append @@ -4780,15 +4776,15 @@ SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.c = t2 Hash Cond: ((t1_2.a = t2_2.a) AND (t1_2.c = t2_2.c)) -> Append -> Seq Scan on alpha_neg_p1 t1_2 - Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND(b < 210)))) + Filter: ((b >= 100) AND (b < 110) AND (c = ANY ('{0004,0009}'::text[]))) -> Seq Scan on alpha_neg_p2 t1_3 - Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND(b < 210)))) + Filter: ((b >= 200) AND (b < 210) AND (c = ANY ('{0004,0009}'::text[]))) -> Hash -> Append -> Seq Scan on beta_neg_p1 t2_2 - Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))) + Filter: ((b >= 100) AND (b < 110)) -> Seq Scan on beta_neg_p2 t2_3 - Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))) + Filter: ((b >= 200) AND (b < 210)) -> Nested Loop Join Filter: ((t1_4.a = t2_4.a) AND (t1_4.c = t2_4.c)) -> Seq Scan on alpha_pos_p2 t1_4 @@ -4834,17 +4830,17 @@ SELECT t1.*, t2.* FROM alpha t1 INNER JOIN beta t2 ON (t1.a = t2.a AND t1.b = t2 -> Hash Join Hash Cond: ((t1_1.a = t2_1.a) AND (t1_1.b = t2_1.b) AND (t1_1.c = t2_1.c)) -> Seq Scan on alpha_neg_p1 t1_1 - Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b <210)))) + Filter: ((b >= 100) AND (b < 110) AND (c = ANY ('{0004,0009}'::text[]))) -> Hash -> Seq Scan on beta_neg_p1 t2_1 - Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))) + Filter: ((b >= 100) AND (b < 110)) -> Hash Join Hash Cond: ((t1_2.a = t2_2.a) AND (t1_2.b = t2_2.b) AND (t1_2.c = t2_2.c)) -> Seq Scan on alpha_neg_p2 t1_2 - Filter: ((c = ANY ('{0004,0009}'::text[])) AND (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b <210)))) + Filter: ((b >= 200) AND (b < 210) AND (c = ANY ('{0004,0009}'::text[]))) -> Hash -> Seq Scan on beta_neg_p2 t2_2 - Filter: (((b >= 100) AND (b < 110)) OR ((b >= 200) AND (b < 210))) + Filter: ((b >= 200) AND (b < 210)) -> Nested Loop Join Filter: ((t1_3.a = t2_3.a) AND (t1_3.b = t2_3.b) AND (t1_3.c = t2_3.c)) -> Seq Scan on alpha_pos_p2 t1_3 diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index c72a6d051f..85f536b143 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -27,22 +27,20 @@ explain (costs off) select * from lp where a > 'a' and a < 'd'; ----------------------------------------------------------- Append -> Seq Scan on lp_bc lp_1 - Filter: ((a > 'a'::bpchar) AND (a < 'd'::bpchar)) -> Seq Scan on lp_default lp_2 Filter: ((a > 'a'::bpchar) AND (a < 'd'::bpchar)) -(5 rows) +(4 rows) explain (costs off) select * from lp where a > 'a' and a <= 'd'; QUERY PLAN ------------------------------------------------------------ Append -> Seq Scan on lp_ad lp_1 - Filter: ((a > 'a'::bpchar) AND (a <= 'd'::bpchar)) + Filter: (a > 'a'::bpchar) -> Seq Scan on lp_bc lp_2 - Filter: ((a > 'a'::bpchar) AND (a <= 'd'::bpchar)) -> Seq Scan on lp_default lp_3 Filter: ((a > 'a'::bpchar) AND (a <= 'd'::bpchar)) -(7 rows) +(6 rows) explain (costs off) select * from lp where a = 'a'; QUERY PLAN @@ -63,85 +61,67 @@ explain (costs off) select * from lp where a is not null; ----------------------------------- Append -> Seq Scan on lp_ad lp_1 - Filter: (a IS NOT NULL) -> Seq Scan on lp_bc lp_2 - Filter: (a IS NOT NULL) -> Seq Scan on lp_ef lp_3 - Filter: (a IS NOT NULL) -> Seq Scan on lp_g lp_4 - Filter: (a IS NOT NULL) -> Seq Scan on lp_default lp_5 - Filter: (a IS NOT NULL) -(11 rows) +(6 rows) explain (costs off) select * from lp where a is null; QUERY PLAN ------------------------ Seq Scan on lp_null lp - Filter: (a IS NULL) -(2 rows) +(1 row) explain (costs off) select * from lp where a = 'a' or a = 'c'; - QUERY PLAN ----------------------------------------------------------- + QUERY PLAN +----------------------------------- Append -> Seq Scan on lp_ad lp_1 - Filter: ((a = 'a'::bpchar) OR (a = 'c'::bpchar)) + Filter: (a = 'a'::bpchar) -> Seq Scan on lp_bc lp_2 - Filter: ((a = 'a'::bpchar) OR (a = 'c'::bpchar)) + Filter: (a = 'c'::bpchar) (5 rows) explain (costs off) select * from lp where a is not null and (a = 'a' or a = 'c'); - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------- Append -> Seq Scan on lp_ad lp_1 - Filter: ((a IS NOT NULL) AND ((a = 'a'::bpchar) OR (a = 'c'::bpchar))) + Filter: (a = 'a'::bpchar) -> Seq Scan on lp_bc lp_2 - Filter: ((a IS NOT NULL) AND ((a = 'a'::bpchar) OR (a = 'c'::bpchar))) + Filter: (a = 'c'::bpchar) (5 rows) explain (costs off) select * from lp where a <> 'g'; - QUERY PLAN ------------------------------------- + QUERY PLAN +----------------------------------- Append -> Seq Scan on lp_ad lp_1 - Filter: (a <> 'g'::bpchar) -> Seq Scan on lp_bc lp_2 - Filter: (a <> 'g'::bpchar) -> Seq Scan on lp_ef lp_3 - Filter: (a <> 'g'::bpchar) -> Seq Scan on lp_default lp_4 - Filter: (a <> 'g'::bpchar) -(9 rows) +(5 rows) explain (costs off) select * from lp where a <> 'a' and a <> 'd'; - QUERY PLAN -------------------------------------------------------------- + QUERY PLAN +----------------------------------- Append -> Seq Scan on lp_bc lp_1 - Filter: ((a <> 'a'::bpchar) AND (a <> 'd'::bpchar)) -> Seq Scan on lp_ef lp_2 - Filter: ((a <> 'a'::bpchar) AND (a <> 'd'::bpchar)) -> Seq Scan on lp_g lp_3 - Filter: ((a <> 'a'::bpchar) AND (a <> 'd'::bpchar)) -> Seq Scan on lp_default lp_4 - Filter: ((a <> 'a'::bpchar) AND (a <> 'd'::bpchar)) -(9 rows) +(5 rows) explain (costs off) select * from lp where a not in ('a', 'd'); - QUERY PLAN ------------------------------------------------- + QUERY PLAN +----------------------------------- Append -> Seq Scan on lp_bc lp_1 - Filter: (a <> ALL ('{a,d}'::bpchar[])) -> Seq Scan on lp_ef lp_2 - Filter: (a <> ALL ('{a,d}'::bpchar[])) -> Seq Scan on lp_g lp_3 - Filter: (a <> ALL ('{a,d}'::bpchar[])) -> Seq Scan on lp_default lp_4 - Filter: (a <> ALL ('{a,d}'::bpchar[])) -(9 rows) +(5 rows) -- collation matches the partitioning collation, pruning works create table coll_pruning (a text collate "C") partition by list (a); @@ -152,8 +132,7 @@ explain (costs off) select * from coll_pruning where a collate "C" = 'a' collate QUERY PLAN ----------------------------------------- Seq Scan on coll_pruning_a coll_pruning - Filter: (a = 'a'::text COLLATE "C") -(2 rows) +(1 row) -- collation doesn't match the partitioning collation, no pruning occurs explain (costs off) select * from coll_pruning where a collate "POSIX" = 'a' collate "POSIX"; @@ -193,25 +172,22 @@ explain (costs off) select * from rlp where a < 1; QUERY PLAN ---------------------- Seq Scan on rlp1 rlp - Filter: (a < 1) -(2 rows) +(1 row) explain (costs off) select * from rlp where 1 > a; /* commuted */ QUERY PLAN ---------------------- Seq Scan on rlp1 rlp - Filter: (1 > a) -(2 rows) +(1 row) explain (costs off) select * from rlp where a <= 1; QUERY PLAN ------------------------------ Append -> Seq Scan on rlp1 rlp_1 - Filter: (a <= 1) -> Seq Scan on rlp2 rlp_2 Filter: (a <= 1) -(5 rows) +(4 rows) explain (costs off) select * from rlp where a = 1; QUERY PLAN @@ -268,65 +244,47 @@ explain (costs off) select * from rlp where a <= 10; --------------------------------------------- Append -> Seq Scan on rlp1 rlp_1 - Filter: (a <= 10) -> Seq Scan on rlp2 rlp_2 - Filter: (a <= 10) -> Seq Scan on rlp_default_10 rlp_3 - Filter: (a <= 10) -> Seq Scan on rlp_default_default rlp_4 Filter: (a <= 10) -(9 rows) +(6 rows) explain (costs off) select * from rlp where a > 10; QUERY PLAN ---------------------------------------------- Append -> Seq Scan on rlp3abcd rlp_1 - Filter: (a > 10) -> Seq Scan on rlp3efgh rlp_2 - Filter: (a > 10) -> Seq Scan on rlp3nullxy rlp_3 - Filter: (a > 10) -> Seq Scan on rlp3_default rlp_4 - Filter: (a > 10) -> Seq Scan on rlp4_1 rlp_5 - Filter: (a > 10) -> Seq Scan on rlp4_2 rlp_6 - Filter: (a > 10) -> Seq Scan on rlp4_default rlp_7 - Filter: (a > 10) -> Seq Scan on rlp5_1 rlp_8 - Filter: (a > 10) -> Seq Scan on rlp5_default rlp_9 - Filter: (a > 10) -> Seq Scan on rlp_default_30 rlp_10 - Filter: (a > 10) -> Seq Scan on rlp_default_default rlp_11 Filter: (a > 10) -(23 rows) +(13 rows) explain (costs off) select * from rlp where a < 15; QUERY PLAN --------------------------------------------- Append -> Seq Scan on rlp1 rlp_1 - Filter: (a < 15) -> Seq Scan on rlp2 rlp_2 - Filter: (a < 15) -> Seq Scan on rlp_default_10 rlp_3 - Filter: (a < 15) -> Seq Scan on rlp_default_default rlp_4 Filter: (a < 15) -(9 rows) +(6 rows) explain (costs off) select * from rlp where a <= 15; QUERY PLAN --------------------------------------------- Append -> Seq Scan on rlp1 rlp_1 - Filter: (a <= 15) -> Seq Scan on rlp2 rlp_2 - Filter: (a <= 15) -> Seq Scan on rlp3abcd rlp_3 Filter: (a <= 15) -> Seq Scan on rlp3efgh rlp_4 @@ -336,10 +294,9 @@ explain (costs off) select * from rlp where a <= 15; -> Seq Scan on rlp3_default rlp_6 Filter: (a <= 15) -> Seq Scan on rlp_default_10 rlp_7 - Filter: (a <= 15) -> Seq Scan on rlp_default_default rlp_8 Filter: (a <= 15) -(17 rows) +(14 rows) explain (costs off) select * from rlp where a > 15 and b = 'ab'; QUERY PLAN @@ -348,17 +305,17 @@ explain (costs off) select * from rlp where a > 15 and b = 'ab'; -> Seq Scan on rlp3abcd rlp_1 Filter: ((a > 15) AND ((b)::text = 'ab'::text)) -> Seq Scan on rlp4_1 rlp_2 - Filter: ((a > 15) AND ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp4_2 rlp_3 - Filter: ((a > 15) AND ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp4_default rlp_4 - Filter: ((a > 15) AND ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp5_1 rlp_5 - Filter: ((a > 15) AND ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp5_default rlp_6 - Filter: ((a > 15) AND ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp_default_30 rlp_7 - Filter: ((a > 15) AND ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp_default_default rlp_8 Filter: ((a > 15) AND ((b)::text = 'ab'::text)) (17 rows) @@ -413,106 +370,77 @@ explain (costs off) select * from rlp where a = 16 and b is not null; ------------------------------------------------ Append -> Seq Scan on rlp3abcd rlp_1 - Filter: ((b IS NOT NULL) AND (a = 16)) + Filter: (a = 16) -> Seq Scan on rlp3efgh rlp_2 - Filter: ((b IS NOT NULL) AND (a = 16)) + Filter: (a = 16) -> Seq Scan on rlp3nullxy rlp_3 Filter: ((b IS NOT NULL) AND (a = 16)) -> Seq Scan on rlp3_default rlp_4 - Filter: ((b IS NOT NULL) AND (a = 16)) + Filter: (a = 16) (9 rows) explain (costs off) select * from rlp where a is null; QUERY PLAN ---------------------------------- Seq Scan on rlp_default_null rlp - Filter: (a IS NULL) -(2 rows) +(1 row) explain (costs off) select * from rlp where a is not null; QUERY PLAN ---------------------------------------------- Append -> Seq Scan on rlp1 rlp_1 - Filter: (a IS NOT NULL) -> Seq Scan on rlp2 rlp_2 - Filter: (a IS NOT NULL) -> Seq Scan on rlp3abcd rlp_3 - Filter: (a IS NOT NULL) -> Seq Scan on rlp3efgh rlp_4 - Filter: (a IS NOT NULL) -> Seq Scan on rlp3nullxy rlp_5 - Filter: (a IS NOT NULL) -> Seq Scan on rlp3_default rlp_6 - Filter: (a IS NOT NULL) -> Seq Scan on rlp4_1 rlp_7 - Filter: (a IS NOT NULL) -> Seq Scan on rlp4_2 rlp_8 - Filter: (a IS NOT NULL) -> Seq Scan on rlp4_default rlp_9 - Filter: (a IS NOT NULL) -> Seq Scan on rlp5_1 rlp_10 - Filter: (a IS NOT NULL) -> Seq Scan on rlp5_default rlp_11 - Filter: (a IS NOT NULL) -> Seq Scan on rlp_default_10 rlp_12 - Filter: (a IS NOT NULL) -> Seq Scan on rlp_default_30 rlp_13 - Filter: (a IS NOT NULL) -> Seq Scan on rlp_default_default rlp_14 - Filter: (a IS NOT NULL) -(29 rows) +(15 rows) explain (costs off) select * from rlp where a > 30; QUERY PLAN --------------------------------------------- Append -> Seq Scan on rlp5_1 rlp_1 - Filter: (a > 30) -> Seq Scan on rlp5_default rlp_2 - Filter: (a > 30) -> Seq Scan on rlp_default_default rlp_3 Filter: (a > 30) -(7 rows) +(5 rows) explain (costs off) select * from rlp where a = 30; /* only default is scanned */ QUERY PLAN -------------------------------- Seq Scan on rlp_default_30 rlp - Filter: (a = 30) -(2 rows) +(1 row) explain (costs off) select * from rlp where a <= 31; QUERY PLAN ---------------------------------------------- Append -> Seq Scan on rlp1 rlp_1 - Filter: (a <= 31) -> Seq Scan on rlp2 rlp_2 - Filter: (a <= 31) -> Seq Scan on rlp3abcd rlp_3 - Filter: (a <= 31) -> Seq Scan on rlp3efgh rlp_4 - Filter: (a <= 31) -> Seq Scan on rlp3nullxy rlp_5 - Filter: (a <= 31) -> Seq Scan on rlp3_default rlp_6 - Filter: (a <= 31) -> Seq Scan on rlp4_1 rlp_7 - Filter: (a <= 31) -> Seq Scan on rlp4_2 rlp_8 - Filter: (a <= 31) -> Seq Scan on rlp4_default rlp_9 - Filter: (a <= 31) -> Seq Scan on rlp5_1 rlp_10 Filter: (a <= 31) -> Seq Scan on rlp_default_10 rlp_11 - Filter: (a <= 31) -> Seq Scan on rlp_default_30 rlp_12 - Filter: (a <= 31) -> Seq Scan on rlp_default_default rlp_13 Filter: (a <= 31) -(27 rows) +(16 rows) explain (costs off) select * from rlp where a = 1 or a = 7; QUERY PLAN @@ -526,39 +454,39 @@ explain (costs off) select * from rlp where a = 1 or b = 'ab'; ------------------------------------------------------- Append -> Seq Scan on rlp1 rlp_1 - Filter: ((a = 1) OR ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp2 rlp_2 Filter: ((a = 1) OR ((b)::text = 'ab'::text)) -> Seq Scan on rlp3abcd rlp_3 - Filter: ((a = 1) OR ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp4_1 rlp_4 - Filter: ((a = 1) OR ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp4_2 rlp_5 - Filter: ((a = 1) OR ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp4_default rlp_6 - Filter: ((a = 1) OR ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp5_1 rlp_7 - Filter: ((a = 1) OR ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp5_default rlp_8 - Filter: ((a = 1) OR ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp_default_10 rlp_9 - Filter: ((a = 1) OR ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp_default_30 rlp_10 - Filter: ((a = 1) OR ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp_default_null rlp_11 - Filter: ((a = 1) OR ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) -> Seq Scan on rlp_default_default rlp_12 - Filter: ((a = 1) OR ((b)::text = 'ab'::text)) + Filter: ((b)::text = 'ab'::text) (25 rows) explain (costs off) select * from rlp where a > 20 and a < 27; - QUERY PLAN ------------------------------------------ + QUERY PLAN +-------------------------------- Append -> Seq Scan on rlp4_1 rlp_1 - Filter: ((a > 20) AND (a < 27)) + Filter: (a > 20) -> Seq Scan on rlp4_2 rlp_2 - Filter: ((a > 20) AND (a < 27)) + Filter: (a < 27) (5 rows) explain (costs off) select * from rlp where a = 29; @@ -575,34 +503,30 @@ explain (costs off) select * from rlp where a >= 29; -> Seq Scan on rlp4_default rlp_1 Filter: (a >= 29) -> Seq Scan on rlp5_1 rlp_2 - Filter: (a >= 29) -> Seq Scan on rlp5_default rlp_3 - Filter: (a >= 29) -> Seq Scan on rlp_default_30 rlp_4 - Filter: (a >= 29) -> Seq Scan on rlp_default_default rlp_5 Filter: (a >= 29) -(11 rows) +(8 rows) explain (costs off) select * from rlp where a < 1 or (a > 20 and a < 25); - QUERY PLAN ------------------------------------------------------- + QUERY PLAN +----------------------------------------- Append -> Seq Scan on rlp1 rlp_1 - Filter: ((a < 1) OR ((a > 20) AND (a < 25))) -> Seq Scan on rlp4_1 rlp_2 - Filter: ((a < 1) OR ((a > 20) AND (a < 25))) -(5 rows) + Filter: ((a > 20) AND (a < 25)) +(4 rows) -- where clause contradicts sub-partition's constraint explain (costs off) select * from rlp where a = 20 or a = 40; - QUERY PLAN ----------------------------------------- + QUERY PLAN +-------------------------------------- Append -> Seq Scan on rlp4_1 rlp_1 - Filter: ((a = 20) OR (a = 40)) + Filter: (a = 20) -> Seq Scan on rlp5_default rlp_2 - Filter: ((a = 20) OR (a = 40)) + Filter: (a = 40) (5 rows) explain (costs off) select * from rlp3 where a = 20; /* empty */ @@ -614,39 +538,28 @@ explain (costs off) select * from rlp3 where a = 20; /* empty */ -- redundant clauses are eliminated explain (costs off) select * from rlp where a > 1 and a = 10; /* only default */ - QUERY PLAN ----------------------------------- + QUERY PLAN +-------------------------------- Seq Scan on rlp_default_10 rlp - Filter: ((a > 1) AND (a = 10)) -(2 rows) +(1 row) explain (costs off) select * from rlp where a > 1 and a >=15; /* rlp3 onwards, including default */ QUERY PLAN ---------------------------------------------- Append -> Seq Scan on rlp3abcd rlp_1 - Filter: ((a > 1) AND (a >= 15)) -> Seq Scan on rlp3efgh rlp_2 - Filter: ((a > 1) AND (a >= 15)) -> Seq Scan on rlp3nullxy rlp_3 - Filter: ((a > 1) AND (a >= 15)) -> Seq Scan on rlp3_default rlp_4 - Filter: ((a > 1) AND (a >= 15)) -> Seq Scan on rlp4_1 rlp_5 - Filter: ((a > 1) AND (a >= 15)) -> Seq Scan on rlp4_2 rlp_6 - Filter: ((a > 1) AND (a >= 15)) -> Seq Scan on rlp4_default rlp_7 - Filter: ((a > 1) AND (a >= 15)) -> Seq Scan on rlp5_1 rlp_8 - Filter: ((a > 1) AND (a >= 15)) -> Seq Scan on rlp5_default rlp_9 - Filter: ((a > 1) AND (a >= 15)) -> Seq Scan on rlp_default_30 rlp_10 - Filter: ((a > 1) AND (a >= 15)) -> Seq Scan on rlp_default_default rlp_11 Filter: ((a > 1) AND (a >= 15)) -(23 rows) +(13 rows) explain (costs off) select * from rlp where a = 1 and a = 3; /* empty */ QUERY PLAN @@ -656,19 +569,19 @@ explain (costs off) select * from rlp where a = 1 and a = 3; /* empty */ (2 rows) explain (costs off) select * from rlp where (a = 1 and a = 3) or (a > 1 and a = 15); - QUERY PLAN -------------------------------------------------------------------- + QUERY PLAN +---------------------------------------- Append -> Seq Scan on rlp2 rlp_1 - Filter: (((a = 1) AND (a = 3)) OR ((a > 1) AND (a = 15))) + Filter: ((a = 1) AND (a = 3)) -> Seq Scan on rlp3abcd rlp_2 - Filter: (((a = 1) AND (a = 3)) OR ((a > 1) AND (a = 15))) + Filter: ((a > 1) AND (a = 15)) -> Seq Scan on rlp3efgh rlp_3 - Filter: (((a = 1) AND (a = 3)) OR ((a > 1) AND (a = 15))) + Filter: ((a > 1) AND (a = 15)) -> Seq Scan on rlp3nullxy rlp_4 - Filter: (((a = 1) AND (a = 3)) OR ((a > 1) AND (a = 15))) + Filter: ((a > 1) AND (a = 15)) -> Seq Scan on rlp3_default rlp_5 - Filter: (((a = 1) AND (a = 3)) OR ((a > 1) AND (a = 15))) + Filter: ((a > 1) AND (a = 15)) (11 rows) -- multi-column keys @@ -733,28 +646,23 @@ explain (costs off) select * from mc3p where a = 10 and abs(b) between 5 and 35; -> Seq Scan on mc3p1 mc3p_1 Filter: ((a = 10) AND (abs(b) >= 5) AND (abs(b) <= 35)) -> Seq Scan on mc3p2 mc3p_2 - Filter: ((a = 10) AND (abs(b) >= 5) AND (abs(b) <= 35)) -> Seq Scan on mc3p3 mc3p_3 - Filter: ((a = 10) AND (abs(b) >= 5) AND (abs(b) <= 35)) -> Seq Scan on mc3p4 mc3p_4 - Filter: ((a = 10) AND (abs(b) >= 5) AND (abs(b) <= 35)) + Filter: (abs(b) <= 35) -> Seq Scan on mc3p_default mc3p_5 Filter: ((a = 10) AND (abs(b) >= 5) AND (abs(b) <= 35)) -(11 rows) +(9 rows) explain (costs off) select * from mc3p where a > 10; QUERY PLAN --------------------------------------- Append -> Seq Scan on mc3p5 mc3p_1 - Filter: (a > 10) -> Seq Scan on mc3p6 mc3p_2 - Filter: (a > 10) -> Seq Scan on mc3p7 mc3p_3 - Filter: (a > 10) -> Seq Scan on mc3p_default mc3p_4 Filter: (a > 10) -(9 rows) +(6 rows) explain (costs off) select * from mc3p where a >= 10; QUERY PLAN @@ -763,43 +671,36 @@ explain (costs off) select * from mc3p where a >= 10; -> Seq Scan on mc3p1 mc3p_1 Filter: (a >= 10) -> Seq Scan on mc3p2 mc3p_2 - Filter: (a >= 10) -> Seq Scan on mc3p3 mc3p_3 - Filter: (a >= 10) -> Seq Scan on mc3p4 mc3p_4 - Filter: (a >= 10) -> Seq Scan on mc3p5 mc3p_5 - Filter: (a >= 10) -> Seq Scan on mc3p6 mc3p_6 - Filter: (a >= 10) -> Seq Scan on mc3p7 mc3p_7 - Filter: (a >= 10) -> Seq Scan on mc3p_default mc3p_8 Filter: (a >= 10) -(17 rows) +(11 rows) explain (costs off) select * from mc3p where a < 10; QUERY PLAN --------------------------------------- Append -> Seq Scan on mc3p0 mc3p_1 - Filter: (a < 10) -> Seq Scan on mc3p1 mc3p_2 Filter: (a < 10) -> Seq Scan on mc3p_default mc3p_3 Filter: (a < 10) -(7 rows) +(6 rows) explain (costs off) select * from mc3p where a <= 10 and abs(b) < 10; QUERY PLAN ----------------------------------------------- Append -> Seq Scan on mc3p0 mc3p_1 - Filter: ((a <= 10) AND (abs(b) < 10)) + Filter: (abs(b) < 10) -> Seq Scan on mc3p1 mc3p_2 - Filter: ((a <= 10) AND (abs(b) < 10)) + Filter: (abs(b) < 10) -> Seq Scan on mc3p2 mc3p_3 - Filter: ((a <= 10) AND (abs(b) < 10)) + Filter: (abs(b) < 10) -> Seq Scan on mc3p_default mc3p_4 Filter: ((a <= 10) AND (abs(b) < 10)) (9 rows) @@ -812,10 +713,10 @@ explain (costs off) select * from mc3p where a = 11 and abs(b) = 0; (2 rows) explain (costs off) select * from mc3p where a = 20 and abs(b) = 10 and c = 100; - QUERY PLAN ------------------------------------------------------- + QUERY PLAN +----------------------------------------- Seq Scan on mc3p6 mc3p - Filter: ((a = 20) AND (c = 100) AND (abs(b) = 10)) + Filter: ((c = 100) AND (abs(b) = 10)) (2 rows) explain (costs off) select * from mc3p where a > 20; @@ -835,23 +736,21 @@ explain (costs off) select * from mc3p where a >= 20; -> Seq Scan on mc3p5 mc3p_1 Filter: (a >= 20) -> Seq Scan on mc3p6 mc3p_2 - Filter: (a >= 20) -> Seq Scan on mc3p7 mc3p_3 - Filter: (a >= 20) -> Seq Scan on mc3p_default mc3p_4 Filter: (a >= 20) -(9 rows) +(7 rows) explain (costs off) select * from mc3p where (a = 1 and abs(b) = 1 and c = 1) or (a = 10 and abs(b) = 5 and c = 10) or (a> 11 and a < 20); QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- Append -> Seq Scan on mc3p1 mc3p_1 - Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a< 20))) + Filter: ((a = 1) AND (c = 1) AND (abs(b) = 1)) -> Seq Scan on mc3p2 mc3p_2 - Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a< 20))) + Filter: ((a = 10) AND (c = 10) AND (abs(b) = 5)) -> Seq Scan on mc3p5 mc3p_3 - Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a< 20))) + Filter: ((a > 11) AND (a < 20)) -> Seq Scan on mc3p_default mc3p_4 Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a< 20))) (9 rows) @@ -861,13 +760,13 @@ explain (costs off) select * from mc3p where (a = 1 and abs(b) = 1 and c = 1) or -------------------------------------------------------------------------------------------------------------------------------------------- Append -> Seq Scan on mc3p0 mc3p_1 - Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a< 20)) OR (a < 1)) + Filter: (a < 1) -> Seq Scan on mc3p1 mc3p_2 - Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a< 20)) OR (a < 1)) + Filter: ((a = 1) AND (c = 1) AND (abs(b) = 1)) -> Seq Scan on mc3p2 mc3p_3 - Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a< 20)) OR (a < 1)) + Filter: ((a = 10) AND (c = 10) AND (abs(b) = 5)) -> Seq Scan on mc3p5 mc3p_4 - Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a< 20)) OR (a < 1)) + Filter: ((a > 11) AND (a < 20)) -> Seq Scan on mc3p_default mc3p_5 Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a< 20)) OR (a < 1)) (11 rows) @@ -877,13 +776,13 @@ explain (costs off) select * from mc3p where (a = 1 and abs(b) = 1 and c = 1) or ------------------------------------------------------------------------------------------------------------------------------------------------------- Append -> Seq Scan on mc3p0 mc3p_1 - Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a< 20)) OR (a < 1) OR (a = 1)) + Filter: ((a < 1) OR (a = 1)) -> Seq Scan on mc3p1 mc3p_2 - Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a< 20)) OR (a < 1) OR (a = 1)) + Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR (a = 1)) -> Seq Scan on mc3p2 mc3p_3 - Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a< 20)) OR (a < 1) OR (a = 1)) + Filter: ((a = 10) AND (c = 10) AND (abs(b) = 5)) -> Seq Scan on mc3p5 mc3p_4 - Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a< 20)) OR (a < 1) OR (a = 1)) + Filter: ((a > 11) AND (a < 20)) -> Seq Scan on mc3p_default mc3p_5 Filter: (((a = 1) AND (abs(b) = 1) AND (c = 1)) OR ((a = 10) AND (abs(b) = 5) AND (c = 10)) OR ((a > 11) AND (a< 20)) OR (a < 1) OR (a = 1)) (11 rows) @@ -897,17 +796,17 @@ explain (costs off) select * from mc3p where a = 1 or abs(b) = 1 or c = 1; -> Seq Scan on mc3p1 mc3p_2 Filter: ((a = 1) OR (abs(b) = 1) OR (c = 1)) -> Seq Scan on mc3p2 mc3p_3 - Filter: ((a = 1) OR (abs(b) = 1) OR (c = 1)) + Filter: (c = 1) -> Seq Scan on mc3p3 mc3p_4 Filter: ((a = 1) OR (abs(b) = 1) OR (c = 1)) -> Seq Scan on mc3p4 mc3p_5 - Filter: ((a = 1) OR (abs(b) = 1) OR (c = 1)) + Filter: (c = 1) -> Seq Scan on mc3p5 mc3p_6 - Filter: ((a = 1) OR (abs(b) = 1) OR (c = 1)) + Filter: ((abs(b) = 1) OR (c = 1)) -> Seq Scan on mc3p6 mc3p_7 - Filter: ((a = 1) OR (abs(b) = 1) OR (c = 1)) + Filter: (c = 1) -> Seq Scan on mc3p7 mc3p_8 - Filter: ((a = 1) OR (abs(b) = 1) OR (c = 1)) + Filter: ((abs(b) = 1) OR (c = 1)) -> Seq Scan on mc3p_default mc3p_9 Filter: ((a = 1) OR (abs(b) = 1) OR (c = 1)) (19 rows) @@ -917,29 +816,28 @@ explain (costs off) select * from mc3p where (a = 1 and abs(b) = 1) or (a = 10 a ------------------------------------------------------------------------------ Append -> Seq Scan on mc3p0 mc3p_1 - Filter: (((a = 1) AND (abs(b) = 1)) OR ((a = 10) AND (abs(b) = 10))) + Filter: ((a = 1) AND (abs(b) = 1)) -> Seq Scan on mc3p1 mc3p_2 - Filter: (((a = 1) AND (abs(b) = 1)) OR ((a = 10) AND (abs(b) = 10))) + Filter: ((a = 1) AND (abs(b) = 1)) -> Seq Scan on mc3p2 mc3p_3 - Filter: (((a = 1) AND (abs(b) = 1)) OR ((a = 10) AND (abs(b) = 10))) + Filter: ((a = 10) AND (abs(b) = 10)) -> Seq Scan on mc3p3 mc3p_4 - Filter: (((a = 1) AND (abs(b) = 1)) OR ((a = 10) AND (abs(b) = 10))) -> Seq Scan on mc3p4 mc3p_5 - Filter: (((a = 1) AND (abs(b) = 1)) OR ((a = 10) AND (abs(b) = 10))) + Filter: ((a = 10) AND (abs(b) = 10)) -> Seq Scan on mc3p_default mc3p_6 Filter: (((a = 1) AND (abs(b) = 1)) OR ((a = 10) AND (abs(b) = 10))) -(13 rows) +(12 rows) explain (costs off) select * from mc3p where (a = 1 and abs(b) = 1) or (a = 10 and abs(b) = 9); QUERY PLAN ----------------------------------------------------------------------------- Append -> Seq Scan on mc3p0 mc3p_1 - Filter: (((a = 1) AND (abs(b) = 1)) OR ((a = 10) AND (abs(b) = 9))) + Filter: ((a = 1) AND (abs(b) = 1)) -> Seq Scan on mc3p1 mc3p_2 - Filter: (((a = 1) AND (abs(b) = 1)) OR ((a = 10) AND (abs(b) = 9))) + Filter: ((a = 1) AND (abs(b) = 1)) -> Seq Scan on mc3p2 mc3p_3 - Filter: (((a = 1) AND (abs(b) = 1)) OR ((a = 10) AND (abs(b) = 9))) + Filter: ((a = 10) AND (abs(b) = 9)) -> Seq Scan on mc3p_default mc3p_4 Filter: (((a = 1) AND (abs(b) = 1)) OR ((a = 10) AND (abs(b) = 9))) (9 rows) @@ -958,21 +856,17 @@ explain (costs off) select * from mc2p where a < 2; --------------------------------------- Append -> Seq Scan on mc2p0 mc2p_1 - Filter: (a < 2) -> Seq Scan on mc2p1 mc2p_2 - Filter: (a < 2) -> Seq Scan on mc2p2 mc2p_3 - Filter: (a < 2) -> Seq Scan on mc2p_default mc2p_4 Filter: (a < 2) -(9 rows) +(6 rows) explain (costs off) select * from mc2p where a = 2 and b < 1; - QUERY PLAN ---------------------------------- + QUERY PLAN +------------------------ Seq Scan on mc2p3 mc2p - Filter: ((b < 1) AND (a = 2)) -(2 rows) +(1 row) explain (costs off) select * from mc2p where a > 1; QUERY PLAN @@ -981,14 +875,11 @@ explain (costs off) select * from mc2p where a > 1; -> Seq Scan on mc2p2 mc2p_1 Filter: (a > 1) -> Seq Scan on mc2p3 mc2p_2 - Filter: (a > 1) -> Seq Scan on mc2p4 mc2p_3 - Filter: (a > 1) -> Seq Scan on mc2p5 mc2p_4 - Filter: (a > 1) -> Seq Scan on mc2p_default mc2p_5 Filter: (a > 1) -(11 rows) +(8 rows) explain (costs off) select * from mc2p where a = 1 and b > 1; QUERY PLAN @@ -1052,15 +943,13 @@ explain (costs off) select * from boolpart where a = false; QUERY PLAN --------------------------------- Seq Scan on boolpart_f boolpart - Filter: (NOT a) -(2 rows) +(1 row) explain (costs off) select * from boolpart where not a = false; QUERY PLAN --------------------------------- Seq Scan on boolpart_t boolpart - Filter: a -(2 rows) +(1 row) explain (costs off) select * from boolpart where a is true or a is not true; QUERY PLAN @@ -1069,7 +958,7 @@ explain (costs off) select * from boolpart where a is true or a is not true; -> Seq Scan on boolpart_f boolpart_1 Filter: ((a IS TRUE) OR (a IS NOT TRUE)) -> Seq Scan on boolpart_t boolpart_2 - Filter: ((a IS TRUE) OR (a IS NOT TRUE)) + Filter: (a IS TRUE) (5 rows) explain (costs off) select * from boolpart where a is not true; @@ -1117,10 +1006,10 @@ create table boolrangep_ff1 partition of boolrangep for values from ('false', 'f create table boolrangep_ff2 partition of boolrangep for values from ('false', 'false', 50) to ('false', 'false', 100); -- try a more complex case that's been known to trip up pruning in the past explain (costs off) select * from boolrangep where not a and not b and c = 25; - QUERY PLAN ----------------------------------------------- + QUERY PLAN +--------------------------------------- Seq Scan on boolrangep_ff1 boolrangep - Filter: ((NOT a) AND (NOT b) AND (c = 25)) + Filter: (c = 25) (2 rows) -- test scalar-to-array operators @@ -1189,21 +1078,18 @@ explain (costs off) select * from coercepart where a !~ all ('{ab,bc}'); (7 rows) explain (costs off) select * from coercepart where a = any ('{ab,bc}'); - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +---------------------------------------------- Append -> Seq Scan on coercepart_ab coercepart_1 - Filter: ((a)::text = ANY ('{ab,bc}'::text[])) -> Seq Scan on coercepart_bc coercepart_2 - Filter: ((a)::text = ANY ('{ab,bc}'::text[])) -(5 rows) +(3 rows) explain (costs off) select * from coercepart where a = any ('{ab,null}'); - QUERY PLAN ---------------------------------------------------- + QUERY PLAN +-------------------------------------- Seq Scan on coercepart_ab coercepart - Filter: ((a)::text = ANY ('{ab,NULL}'::text[])) -(2 rows) +(1 row) explain (costs off) select * from coercepart where a = any (null::text[]); QUERY PLAN @@ -1213,11 +1099,10 @@ explain (costs off) select * from coercepart where a = any (null::text[]); (2 rows) explain (costs off) select * from coercepart where a = all ('{ab}'); - QUERY PLAN ----------------------------------------------- + QUERY PLAN +-------------------------------------- Seq Scan on coercepart_ab coercepart - Filter: ((a)::text = ALL ('{ab}'::text[])) -(2 rows) +(1 row) explain (costs off) select * from coercepart where a = all ('{ab,bc}'); QUERY PLAN @@ -1289,7 +1174,6 @@ explain (costs off) select * from mc2p t1, lateral (select count(*) from mc3p t2 Nested Loop -> Append -> Seq Scan on mc2p1 t1_1 - Filter: (a = 1) -> Seq Scan on mc2p2 t1_2 Filter: (a = 1) -> Seq Scan on mc2p_default t1_3 @@ -1314,7 +1198,7 @@ explain (costs off) select * from mc2p t1, lateral (select count(*) from mc3p t2 Filter: ((a = t1.b) AND (c = 1) AND (abs(b) = 1)) -> Seq Scan on mc3p_default t2_9 Filter: ((a = t1.b) AND (c = 1) AND (abs(b) = 1)) -(28 rows) +(27 rows) -- pruning should work fine, because values for a prefix of keys (a, b) are -- available @@ -1324,7 +1208,6 @@ explain (costs off) select * from mc2p t1, lateral (select count(*) from mc3p t2 Nested Loop -> Append -> Seq Scan on mc2p1 t1_1 - Filter: (a = 1) -> Seq Scan on mc2p2 t1_2 Filter: (a = 1) -> Seq Scan on mc2p_default t1_3 @@ -1337,7 +1220,7 @@ explain (costs off) select * from mc2p t1, lateral (select count(*) from mc3p t2 Filter: ((c = t1.b) AND (a = 1) AND (abs(b) = 1)) -> Seq Scan on mc3p_default t2_3 Filter: ((c = t1.b) AND (a = 1) AND (abs(b) = 1)) -(16 rows) +(15 rows) -- also here, because values for all keys are provided explain (costs off) select * from mc2p t1, lateral (select count(*) from mc3p t2 where t2.a = 1 and abs(t2.b) = 1 and t2.c= 1) s where t1.a = 1; @@ -1349,12 +1232,11 @@ explain (costs off) select * from mc2p t1, lateral (select count(*) from mc3p t2 Filter: ((a = 1) AND (c = 1) AND (abs(b) = 1)) -> Append -> Seq Scan on mc2p1 t1_1 - Filter: (a = 1) -> Seq Scan on mc2p2 t1_2 Filter: (a = 1) -> Seq Scan on mc2p_default t1_3 Filter: (a = 1) -(11 rows) +(10 rows) -- -- pruning with clauses containing <> operator @@ -1369,24 +1251,21 @@ explain (costs off) select * from rp where a <> 1; ---------------------------- Append -> Seq Scan on rp0 rp_1 - Filter: (a <> 1) -> Seq Scan on rp1 rp_2 Filter: (a <> 1) -> Seq Scan on rp2 rp_3 - Filter: (a <> 1) -(7 rows) +(5 rows) explain (costs off) select * from rp where a <> 1 and a <> 2; - QUERY PLAN ------------------------------------------ + QUERY PLAN +---------------------------- Append -> Seq Scan on rp0 rp_1 - Filter: ((a <> 1) AND (a <> 2)) -> Seq Scan on rp1 rp_2 - Filter: ((a <> 1) AND (a <> 2)) + Filter: (a <> 1) -> Seq Scan on rp2 rp_3 - Filter: ((a <> 1) AND (a <> 2)) -(7 rows) + Filter: (a <> 2) +(6 rows) -- null partition should be eliminated due to strict <> clause. explain (costs off) select * from lp where a <> 'a'; @@ -1396,14 +1275,10 @@ explain (costs off) select * from lp where a <> 'a'; -> Seq Scan on lp_ad lp_1 Filter: (a <> 'a'::bpchar) -> Seq Scan on lp_bc lp_2 - Filter: (a <> 'a'::bpchar) -> Seq Scan on lp_ef lp_3 - Filter: (a <> 'a'::bpchar) -> Seq Scan on lp_g lp_4 - Filter: (a <> 'a'::bpchar) -> Seq Scan on lp_default lp_5 - Filter: (a <> 'a'::bpchar) -(11 rows) +(7 rows) -- ensure we detect contradictions in clauses; a can't be NULL and NOT NULL. explain (costs off) select * from lp where a <> 'a' and a is null; @@ -1414,32 +1289,27 @@ explain (costs off) select * from lp where a <> 'a' and a is null; (2 rows) explain (costs off) select * from lp where (a <> 'a' and a <> 'd') or a is null; - QUERY PLAN ------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------- Append -> Seq Scan on lp_bc lp_1 - Filter: (((a <> 'a'::bpchar) AND (a <> 'd'::bpchar)) OR (a IS NULL)) -> Seq Scan on lp_ef lp_2 - Filter: (((a <> 'a'::bpchar) AND (a <> 'd'::bpchar)) OR (a IS NULL)) -> Seq Scan on lp_g lp_3 - Filter: (((a <> 'a'::bpchar) AND (a <> 'd'::bpchar)) OR (a IS NULL)) -> Seq Scan on lp_null lp_4 - Filter: (((a <> 'a'::bpchar) AND (a <> 'd'::bpchar)) OR (a IS NULL)) -> Seq Scan on lp_default lp_5 - Filter: (((a <> 'a'::bpchar) AND (a <> 'd'::bpchar)) OR (a IS NULL)) -(11 rows) +(6 rows) -- check that it also works for a partitioned table that's not root, -- which in this case are partitions of rlp that are themselves -- list-partitioned on b explain (costs off) select * from rlp where a = 15 and b <> 'ab' and b <> 'cd' and b <> 'xy' and b is not null; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------- + QUERY PLAN +-------------------------------------- Append -> Seq Scan on rlp3efgh rlp_1 - Filter: ((b IS NOT NULL) AND ((b)::text <> 'ab'::text) AND ((b)::text <> 'cd'::text) AND ((b)::text <> 'xy'::text)AND (a = 15)) + Filter: (a = 15) -> Seq Scan on rlp3_default rlp_2 - Filter: ((b IS NOT NULL) AND ((b)::text <> 'ab'::text) AND ((b)::text <> 'cd'::text) AND ((b)::text <> 'xy'::text)AND (a = 15)) + Filter: (a = 15) (5 rows) -- @@ -1780,9 +1650,9 @@ explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 2); Append (actual rows=0 loops=1) Subplans Removed: 4 -> Seq Scan on ab_a2_b1 ab_1 (actual rows=0 loops=1) - Filter: ((a >= $1) AND (a <= $2) AND (b < 3)) + Filter: ((a >= $1) AND (a <= $2)) -> Seq Scan on ab_a2_b2 ab_2 (actual rows=0 loops=1) - Filter: ((a >= $1) AND (a <= $2) AND (b < 3)) + Filter: ((a >= $1) AND (a <= $2)) (6 rows) explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 4); @@ -1791,13 +1661,13 @@ explain (analyze, costs off, summary off, timing off) execute ab_q1 (2, 4); Append (actual rows=0 loops=1) Subplans Removed: 2 -> Seq Scan on ab_a2_b1 ab_1 (actual rows=0 loops=1) - Filter: ((a >= $1) AND (a <= $2) AND (b < 3)) + Filter: ((a >= $1) AND (a <= $2)) -> Seq Scan on ab_a2_b2 ab_2 (actual rows=0 loops=1) - Filter: ((a >= $1) AND (a <= $2) AND (b < 3)) + Filter: ((a >= $1) AND (a <= $2)) -> Seq Scan on ab_a3_b1 ab_3 (actual rows=0 loops=1) - Filter: ((a >= $1) AND (a <= $2) AND (b < 3)) + Filter: ((a >= $1) AND (a <= $2)) -> Seq Scan on ab_a3_b2 ab_4 (actual rows=0 loops=1) - Filter: ((a >= $1) AND (a <= $2) AND (b < 3)) + Filter: ((a >= $1) AND (a <= $2)) (10 rows) -- Ensure a mix of PARAM_EXTERN and PARAM_EXEC Params work together at @@ -1952,11 +1822,11 @@ select explain_parallel_append('execute ab_q4 (2, 2)'); -> Parallel Append (actual rows=N loops=N) Subplans Removed: 6 -> Parallel Seq Scan on ab_a2_b1 ab_1 (actual rows=N loops=N) - Filter: ((a >= $1) AND (a <= $2) AND (b < 4)) + Filter: ((a >= $1) AND (a <= $2)) -> Parallel Seq Scan on ab_a2_b2 ab_2 (actual rows=N loops=N) - Filter: ((a >= $1) AND (a <= $2) AND (b < 4)) + Filter: ((a >= $1) AND (a <= $2)) -> Parallel Seq Scan on ab_a2_b3 ab_3 (actual rows=N loops=N) - Filter: ((a >= $1) AND (a <= $2) AND (b < 4)) + Filter: ((a >= $1) AND (a <= $2)) (13 rows) -- Test run-time pruning with IN lists. @@ -1973,11 +1843,11 @@ select explain_parallel_append('execute ab_q5 (1, 1, 1)'); -> Parallel Append (actual rows=N loops=N) Subplans Removed: 6 -> Parallel Seq Scan on ab_a1_b1 ab_1 (actual rows=N loops=N) - Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3]))) + Filter: (a = ANY (ARRAY[$1, $2, $3])) -> Parallel Seq Scan on ab_a1_b2 ab_2 (actual rows=N loops=N) - Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3]))) + Filter: (a = ANY (ARRAY[$1, $2, $3])) -> Parallel Seq Scan on ab_a1_b3 ab_3 (actual rows=N loops=N) - Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3]))) + Filter: (a = ANY (ARRAY[$1, $2, $3])) (13 rows) select explain_parallel_append('execute ab_q5 (2, 3, 3)'); @@ -1991,17 +1861,17 @@ select explain_parallel_append('execute ab_q5 (2, 3, 3)'); -> Parallel Append (actual rows=N loops=N) Subplans Removed: 3 -> Parallel Seq Scan on ab_a2_b1 ab_1 (actual rows=N loops=N) - Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3]))) + Filter: (a = ANY (ARRAY[$1, $2, $3])) -> Parallel Seq Scan on ab_a2_b2 ab_2 (actual rows=N loops=N) - Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3]))) + Filter: (a = ANY (ARRAY[$1, $2, $3])) -> Parallel Seq Scan on ab_a2_b3 ab_3 (actual rows=N loops=N) - Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3]))) + Filter: (a = ANY (ARRAY[$1, $2, $3])) -> Parallel Seq Scan on ab_a3_b1 ab_4 (actual rows=N loops=N) - Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3]))) + Filter: (a = ANY (ARRAY[$1, $2, $3])) -> Parallel Seq Scan on ab_a3_b2 ab_5 (actual rows=N loops=N) - Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3]))) + Filter: (a = ANY (ARRAY[$1, $2, $3])) -> Parallel Seq Scan on ab_a3_b3 ab_6 (actual rows=N loops=N) - Filter: ((b < 4) AND (a = ANY (ARRAY[$1, $2, $3]))) + Filter: (a = ANY (ARRAY[$1, $2, $3])) (19 rows) -- Try some params whose values do not belong to any partition. @@ -2019,9 +1889,9 @@ select explain_parallel_append('execute ab_q5 (33, 44, 55)'); -- Test Parallel Append with PARAM_EXEC Params select explain_parallel_append('select count(*) from ab where (a = (select 1) or a = (select 3)) and b = 2'); - explain_parallel_append ------------------------------------------------------------------------------- - Aggregate (actual rows=N loops=N) + explain_parallel_append +------------------------------------------------------------------------------------ + Finalize Aggregate (actual rows=N loops=N) InitPlan 1 (returns $0) -> Result (actual rows=N loops=N) InitPlan 2 (returns $1) @@ -2030,14 +1900,15 @@ select explain_parallel_append('select count(*) from ab where (a = (select 1) or Workers Planned: 2 Params Evaluated: $0, $1 Workers Launched: N - -> Parallel Append (actual rows=N loops=N) - -> Parallel Seq Scan on ab_a1_b2 ab_1 (actual rows=N loops=N) - Filter: ((b = 2) AND ((a = $0) OR (a = $1))) - -> Parallel Seq Scan on ab_a2_b2 ab_2 (never executed) - Filter: ((b = 2) AND ((a = $0) OR (a = $1))) - -> Parallel Seq Scan on ab_a3_b2 ab_3 (actual rows=N loops=N) - Filter: ((b = 2) AND ((a = $0) OR (a = $1))) -(16 rows) + -> Partial Aggregate (actual rows=N loops=N) + -> Parallel Append (actual rows=N loops=N) + -> Parallel Seq Scan on ab_a1_b2 ab_1 (actual rows=N loops=N) + Filter: ((a = $0) OR (a = $1)) + -> Parallel Seq Scan on ab_a2_b2 ab_2 (never executed) + Filter: ((a = $0) OR (a = $1)) + -> Parallel Seq Scan on ab_a3_b2 ab_3 (actual rows=N loops=N) + Filter: ((a = $0) OR (a = $1)) +(17 rows) -- Test pruning during parallel nested loop query create table lprt_a (a int not null); @@ -2291,27 +2162,18 @@ select * from ab where a = (select max(a) from lprt_a) and b = (select max(a)-1 -- Test run-time partition pruning with UNION ALL parents explain (analyze, costs off, summary off, timing off) select * from (select * from ab where a = 1 union all select * from ab) ab where b = (select 1); - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------- Append (actual rows=0 loops=1) InitPlan 1 (returns $0) -> Result (actual rows=1 loops=1) -> Append (actual rows=0 loops=1) - -> Bitmap Heap Scan on ab_a1_b1 ab_11 (actual rows=0 loops=1) - Recheck Cond: (a = 1) + -> Seq Scan on ab_a1_b1 ab_11 (actual rows=0 loops=1) Filter: (b = $0) - -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1) - Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b2 ab_12 (never executed) - Recheck Cond: (a = 1) + -> Seq Scan on ab_a1_b2 ab_12 (never executed) Filter: (b = $0) - -> Bitmap Index Scan on ab_a1_b2_a_idx (never executed) - Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b3 ab_13 (never executed) - Recheck Cond: (a = 1) + -> Seq Scan on ab_a1_b3 ab_13 (never executed) Filter: (b = $0) - -> Bitmap Index Scan on ab_a1_b3_a_idx (never executed) - Index Cond: (a = 1) -> Seq Scan on ab_a1_b1 ab_1 (actual rows=0 loops=1) Filter: (b = $0) -> Seq Scan on ab_a1_b2 ab_2 (never executed) @@ -2330,32 +2192,23 @@ select * from (select * from ab where a = 1 union all select * from ab) ab where Filter: (b = $0) -> Seq Scan on ab_a3_b3 ab_9 (never executed) Filter: (b = $0) -(37 rows) +(28 rows) -- A case containing a UNION ALL with a non-partitioned child. explain (analyze, costs off, summary off, timing off) select * from (select * from ab where a = 1 union all (values(10,5)) union all select * from ab) ab where b = (select 1); - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------- Append (actual rows=0 loops=1) InitPlan 1 (returns $0) -> Result (actual rows=1 loops=1) -> Append (actual rows=0 loops=1) - -> Bitmap Heap Scan on ab_a1_b1 ab_11 (actual rows=0 loops=1) - Recheck Cond: (a = 1) + -> Seq Scan on ab_a1_b1 ab_11 (actual rows=0 loops=1) Filter: (b = $0) - -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1) - Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b2 ab_12 (never executed) - Recheck Cond: (a = 1) + -> Seq Scan on ab_a1_b2 ab_12 (never executed) Filter: (b = $0) - -> Bitmap Index Scan on ab_a1_b2_a_idx (never executed) - Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b3 ab_13 (never executed) - Recheck Cond: (a = 1) + -> Seq Scan on ab_a1_b3 ab_13 (never executed) Filter: (b = $0) - -> Bitmap Index Scan on ab_a1_b3_a_idx (never executed) - Index Cond: (a = 1) -> Result (actual rows=0 loops=1) One-Time Filter: (5 = $0) -> Seq Scan on ab_a1_b1 ab_1 (actual rows=0 loops=1) @@ -2376,7 +2229,7 @@ select * from (select * from ab where a = 1 union all (values(10,5)) union all s Filter: (b = $0) -> Seq Scan on ab_a3_b3 ab_9 (never executed) Filter: (b = $0) -(39 rows) +(30 rows) -- Another UNION ALL test, but containing a mix of exec init and exec run-time pruning. create table xy_1 (x int, y int); @@ -2435,74 +2288,34 @@ deallocate ab_q6; insert into ab values (1,2); explain (analyze, costs off, summary off, timing off) update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a; - QUERY PLAN -------------------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------ Update on ab_a1 (actual rows=0 loops=1) Update on ab_a1_b1 ab_a1_1 Update on ab_a1_b2 ab_a1_2 Update on ab_a1_b3 ab_a1_3 -> Nested Loop (actual rows=0 loops=1) -> Append (actual rows=1 loops=1) - -> Bitmap Heap Scan on ab_a1_b1 ab_1 (actual rows=0 loops=1) - Recheck Cond: (a = 1) - -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1) - Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b2 ab_2 (actual rows=1 loops=1) - Recheck Cond: (a = 1) - Heap Blocks: exact=1 - -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1) - Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b3 ab_3 (actual rows=0 loops=1) - Recheck Cond: (a = 1) - -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=0 loops=1) - Index Cond: (a = 1) + -> Seq Scan on ab_a1_b1 ab_1 (actual rows=0 loops=1) + -> Seq Scan on ab_a1_b2 ab_2 (actual rows=1 loops=1) + -> Seq Scan on ab_a1_b3 ab_3 (actual rows=0 loops=1) -> Materialize (actual rows=0 loops=1) - -> Bitmap Heap Scan on ab_a1_b1 ab_a1_1 (actual rows=0 loops=1) - Recheck Cond: (a = 1) - -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1) - Index Cond: (a = 1) + -> Seq Scan on ab_a1_b1 ab_a1_1 (actual rows=0 loops=1) -> Nested Loop (actual rows=1 loops=1) -> Append (actual rows=1 loops=1) - -> Bitmap Heap Scan on ab_a1_b1 ab_1 (actual rows=0 loops=1) - Recheck Cond: (a = 1) - -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1) - Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b2 ab_2 (actual rows=1 loops=1) - Recheck Cond: (a = 1) - Heap Blocks: exact=1 - -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1) - Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b3 ab_3 (actual rows=0 loops=1) - Recheck Cond: (a = 1) - -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=1 loops=1) - Index Cond: (a = 1) + -> Seq Scan on ab_a1_b1 ab_1 (actual rows=0 loops=1) + -> Seq Scan on ab_a1_b2 ab_2 (actual rows=1 loops=1) + -> Seq Scan on ab_a1_b3 ab_3 (actual rows=0 loops=1) -> Materialize (actual rows=1 loops=1) - -> Bitmap Heap Scan on ab_a1_b2 ab_a1_2 (actual rows=1 loops=1) - Recheck Cond: (a = 1) - Heap Blocks: exact=1 - -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1) - Index Cond: (a = 1) + -> Seq Scan on ab_a1_b2 ab_a1_2 (actual rows=1 loops=1) -> Nested Loop (actual rows=0 loops=1) -> Append (actual rows=1 loops=1) - -> Bitmap Heap Scan on ab_a1_b1 ab_1 (actual rows=0 loops=1) - Recheck Cond: (a = 1) - -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1) - Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b2 ab_2 (actual rows=1 loops=1) - Recheck Cond: (a = 1) - Heap Blocks: exact=1 - -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1) - Index Cond: (a = 1) - -> Bitmap Heap Scan on ab_a1_b3 ab_3 (actual rows=0 loops=1) - Recheck Cond: (a = 1) - -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=1 loops=1) - Index Cond: (a = 1) + -> Seq Scan on ab_a1_b1 ab_1 (actual rows=0 loops=1) + -> Seq Scan on ab_a1_b2 ab_2 (actual rows=1 loops=1) + -> Seq Scan on ab_a1_b3 ab_3 (actual rows=0 loops=1) -> Materialize (actual rows=0 loops=1) - -> Bitmap Heap Scan on ab_a1_b3 ab_a1_3 (actual rows=0 loops=1) - Recheck Cond: (a = 1) - -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=1 loops=1) - Index Cond: (a = 1) -(65 rows) + -> Seq Scan on ab_a1_b3 ab_a1_3 (actual rows=0 loops=1) +(25 rows) table ab; a | b @@ -3013,9 +2826,9 @@ select * from mc3p where a < 3 and abs(b) = 1; -------------------------------------------------------- Append (actual rows=3 loops=1) -> Seq Scan on mc3p0 mc3p_1 (actual rows=1 loops=1) - Filter: ((a < 3) AND (abs(b) = 1)) + Filter: (abs(b) = 1) -> Seq Scan on mc3p1 mc3p_2 (actual rows=1 loops=1) - Filter: ((a < 3) AND (abs(b) = 1)) + Filter: (abs(b) = 1) -> Seq Scan on mc3p2 mc3p_3 (actual rows=1 loops=1) Filter: ((a < 3) AND (abs(b) = 1)) (7 rows) @@ -3210,8 +3023,7 @@ explain (costs off) select * from pp_arrpart where a = '{1}'; QUERY PLAN ------------------------------------ Seq Scan on pp_arrpart1 pp_arrpart - Filter: (a = '{1}'::integer[]) -(2 rows) +(1 row) explain (costs off) select * from pp_arrpart where a = '{1, 2}'; QUERY PLAN @@ -3221,14 +3033,13 @@ explain (costs off) select * from pp_arrpart where a = '{1, 2}'; (2 rows) explain (costs off) select * from pp_arrpart where a in ('{4, 5}', '{1}'); - QUERY PLAN ----------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------- Append -> Seq Scan on pp_arrpart1 pp_arrpart_1 - Filter: ((a = '{4,5}'::integer[]) OR (a = '{1}'::integer[])) -> Seq Scan on pp_arrpart2 pp_arrpart_2 - Filter: ((a = '{4,5}'::integer[]) OR (a = '{1}'::integer[])) -(5 rows) + Filter: (a = '{4,5}'::integer[]) +(4 rows) explain (costs off) update pp_arrpart set a = a where a = '{1}'; QUERY PLAN @@ -3236,8 +3047,7 @@ explain (costs off) update pp_arrpart set a = a where a = '{1}'; Update on pp_arrpart Update on pp_arrpart1 pp_arrpart_1 -> Seq Scan on pp_arrpart1 pp_arrpart_1 - Filter: (a = '{1}'::integer[]) -(4 rows) +(3 rows) explain (costs off) delete from pp_arrpart where a = '{1}'; QUERY PLAN @@ -3245,8 +3055,7 @@ explain (costs off) delete from pp_arrpart where a = '{1}'; Delete on pp_arrpart Delete on pp_arrpart1 pp_arrpart_1 -> Seq Scan on pp_arrpart1 pp_arrpart_1 - Filter: (a = '{1}'::integer[]) -(4 rows) +(3 rows) drop table pp_arrpart; -- array type hash partition key @@ -3296,8 +3105,7 @@ explain (costs off) select * from pp_enumpart where a = 'blue'; QUERY PLAN ------------------------------------------ Seq Scan on pp_enumpart_blue pp_enumpart - Filter: (a = 'blue'::pp_colors) -(2 rows) +(1 row) explain (costs off) select * from pp_enumpart where a = 'black'; QUERY PLAN @@ -3317,8 +3125,7 @@ explain (costs off) select * from pp_recpart where a = '(1,1)'::pp_rectype; QUERY PLAN -------------------------------------- Seq Scan on pp_recpart_11 pp_recpart - Filter: (a = '(1,1)'::pp_rectype) -(2 rows) +(1 row) explain (costs off) select * from pp_recpart where a = '(1,2)'::pp_rectype; QUERY PLAN @@ -3337,8 +3144,7 @@ explain (costs off) select * from pp_intrangepart where a = '[1,2]'::int4range; QUERY PLAN ----------------------------------------------- Seq Scan on pp_intrangepart12 pp_intrangepart - Filter: (a = '[1,3)'::int4range) -(2 rows) +(1 row) explain (costs off) select * from pp_intrangepart where a = '(1,2)'::int4range; QUERY PLAN @@ -3358,8 +3164,7 @@ explain (costs off) select * from pp_lp where a = 1; QUERY PLAN -------------------------- Seq Scan on pp_lp1 pp_lp - Filter: (a = 1) -(2 rows) +(1 row) explain (costs off) update pp_lp set value = 10 where a = 1; QUERY PLAN @@ -3367,8 +3172,7 @@ explain (costs off) update pp_lp set value = 10 where a = 1; Update on pp_lp Update on pp_lp1 pp_lp_1 -> Seq Scan on pp_lp1 pp_lp_1 - Filter: (a = 1) -(4 rows) +(3 rows) explain (costs off) delete from pp_lp where a = 1; QUERY PLAN @@ -3376,8 +3180,7 @@ explain (costs off) delete from pp_lp where a = 1; Delete on pp_lp Delete on pp_lp1 pp_lp_1 -> Seq Scan on pp_lp1 pp_lp_1 - Filter: (a = 1) -(4 rows) +(3 rows) set enable_partition_pruning = off; set constraint_exclusion = 'partition'; -- this should not affect the result. @@ -3386,10 +3189,9 @@ explain (costs off) select * from pp_lp where a = 1; ---------------------------------- Append -> Seq Scan on pp_lp1 pp_lp_1 - Filter: (a = 1) -> Seq Scan on pp_lp2 pp_lp_2 Filter: (a = 1) -(5 rows) +(4 rows) explain (costs off) update pp_lp set value = 10 where a = 1; QUERY PLAN @@ -3398,10 +3200,9 @@ explain (costs off) update pp_lp set value = 10 where a = 1; Update on pp_lp1 pp_lp_1 Update on pp_lp2 pp_lp_2 -> Seq Scan on pp_lp1 pp_lp_1 - Filter: (a = 1) -> Seq Scan on pp_lp2 pp_lp_2 Filter: (a = 1) -(7 rows) +(6 rows) explain (costs off) delete from pp_lp where a = 1; QUERY PLAN @@ -3410,10 +3211,9 @@ explain (costs off) delete from pp_lp where a = 1; Delete on pp_lp1 pp_lp_1 Delete on pp_lp2 pp_lp_2 -> Seq Scan on pp_lp1 pp_lp_1 - Filter: (a = 1) -> Seq Scan on pp_lp2 pp_lp_2 Filter: (a = 1) -(7 rows) +(6 rows) set constraint_exclusion = 'off'; -- this should not affect the result. explain (costs off) select * from pp_lp where a = 1; @@ -3553,15 +3353,15 @@ from ( select 1, 1, 1 ) s(a, b, c) where s.a = 1 and s.b = 1 and s.c = (select 1); - QUERY PLAN ----------------------------------------------------- + QUERY PLAN +---------------------------------------- Append InitPlan 1 (returns $0) -> Result -> Seq Scan on p1 p - Filter: ((a = 1) AND (b = 1) AND (c = $0)) + Filter: ((b = 1) AND (c = $0)) -> Seq Scan on q111 q1 - Filter: ((a = 1) AND (b = 1) AND (c = $0)) + Filter: (c = $0) -> Result One-Time Filter: (1 = $0) (9 rows) @@ -3782,10 +3582,10 @@ create table rp_prefix_test1_p2 partition of rp_prefix_test1 for values from (2, -- Don't call get_steps_using_prefix() with the last partition key b plus -- an empty prefix explain (costs off) select * from rp_prefix_test1 where a <= 1 and b = 'a'; - QUERY PLAN --------------------------------------------------- + QUERY PLAN +------------------------------------------------ Seq Scan on rp_prefix_test1_p1 rp_prefix_test1 - Filter: ((a <= 1) AND ((b)::text = 'a'::text)) + Filter: ((b)::text = 'a'::text) (2 rows) create table rp_prefix_test2 (a int, b int, c int) partition by range(a, b, c); @@ -3797,8 +3597,7 @@ explain (costs off) select * from rp_prefix_test2 where a <= 1 and b = 1 and c > QUERY PLAN ------------------------------------------------ Seq Scan on rp_prefix_test2_p1 rp_prefix_test2 - Filter: ((a <= 1) AND (c >= 0) AND (b = 1)) -(2 rows) +(1 row) create table rp_prefix_test3 (a int, b int, c int, d int) partition by range(a, b, c, d); create table rp_prefix_test3_p1 partition of rp_prefix_test3 for values from (1, 1, 1, 0) to (1, 1, 1, 10); @@ -3806,21 +3605,19 @@ create table rp_prefix_test3_p2 partition of rp_prefix_test3 for values from (2, -- Test that get_steps_using_prefix() handles a prefix that contains multiple -- clauses for the partition key b (ie, b >= 1 and b >= 2) explain (costs off) select * from rp_prefix_test3 where a >= 1 and b >= 1 and b >= 2 and c >= 2 and d >= 0; - QUERY PLAN --------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------ Seq Scan on rp_prefix_test3_p2 rp_prefix_test3 - Filter: ((a >= 1) AND (b >= 1) AND (b >= 2) AND (c >= 2) AND (d >= 0)) -(2 rows) +(1 row) -- Test that get_steps_using_prefix() handles a prefix that contains multiple -- clauses for the partition key b (ie, b >= 1 and b = 2) (This also tests -- that the caller arranges clauses in that prefix in the required order) explain (costs off) select * from rp_prefix_test3 where a >= 1 and b >= 1 and b = 2 and c = 2 and d >= 0; - QUERY PLAN ------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------ Seq Scan on rp_prefix_test3_p2 rp_prefix_test3 - Filter: ((a >= 1) AND (b >= 1) AND (d >= 0) AND (b = 2) AND (c = 2)) -(2 rows) +(1 row) create table hp_prefix_test (a int, b int, c int, d int) partition by hash (a part_test_int4_ops, b part_test_int4_ops,c part_test_int4_ops, d part_test_int4_ops); create table hp_prefix_test_p1 partition of hp_prefix_test for values with (modulus 2, remainder 0); diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out index 9506aaef82..3309d26c87 100644 --- a/src/test/regress/expected/rowsecurity.out +++ b/src/test/regress/expected/rowsecurity.out @@ -1057,10 +1057,10 @@ NOTICE: f_leak => awesome science fiction (4 rows) EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle); - QUERY PLAN --------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------- Seq Scan on part_document_fiction part_document - Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle)) + Filter: ((dlevel <= $0) AND f_leak(dtitle)) InitPlan 1 (returns $0) -> Index Scan using uaccount_pkey on uaccount Index Cond: (pguser = CURRENT_USER) @@ -1135,10 +1135,10 @@ NOTICE: f_leak => awesome science fiction (4 rows) EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle); - QUERY PLAN --------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------- Seq Scan on part_document_fiction part_document - Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle)) + Filter: ((dlevel <= $0) AND f_leak(dtitle)) InitPlan 1 (returns $0) -> Index Scan using uaccount_pkey on uaccount Index Cond: (pguser = CURRENT_USER) diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out index bf939d79f6..0d821ade5b 100644 --- a/src/test/regress/expected/update.out +++ b/src/test/regress/expected/update.out @@ -327,12 +327,10 @@ EXPLAIN (costs off) UPDATE range_parted set c = c - 50 WHERE c > 97; -> Seq Scan on part_c_1_100 range_parted_4 Filter: (c > '97'::numeric) -> Seq Scan on part_d_1_15 range_parted_5 - Filter: (c > '97'::numeric) -> Seq Scan on part_d_15_20 range_parted_6 - Filter: (c > '97'::numeric) -> Seq Scan on part_b_20_b_30 range_parted_7 Filter: (c > '97'::numeric) -(22 rows) +(20 rows) -- fail, row movement happens only within the partition subtree. UPDATE part_c_100_200 set c = c - 20, d = c WHERE c = 105;
pgsql-hackers by date: