Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1huSP1-00068P-RG for pgsql-hackers@arkaria.postgresql.org; Mon, 05 Aug 2019 02:07:11 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1huSP0-0000Bw-J4 for pgsql-hackers@arkaria.postgresql.org; Mon, 05 Aug 2019 02:07:10 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1huSLp-0006Ci-3Z for pgsql-hackers@lists.postgresql.org; Mon, 05 Aug 2019 02:03:53 +0000 Received: from mail-qt1-x843.google.com ([2607:f8b0:4864:20::843]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1huSLl-000843-CR for pgsql-hackers@lists.postgresql.org; Mon, 05 Aug 2019 02:03:52 +0000 Received: by mail-qt1-x843.google.com with SMTP id h18so79532603qtm.9 for ; Sun, 04 Aug 2019 19:03:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=2ndquadrant-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:mime-version:content-disposition :content-transfer-encoding:in-reply-to:user-agent; bh=V5khxMwfVI0mTvPhrCOPTTSzbeth0WJ0wlwZQ8iejdk=; b=cOq1MrbidRrtDpC0UMYP/oz3ImLfxgIlHuv/o+odX1SWdoqeGP3YS75ESRb2PpSsXD CsOL6OCun81VS6LeldI068Hgu2Ytx2PoZ7XOnyup5ALZI8fMfWBhv8GkHMIksCBDpetP aOoDS/x2AarbOjvvExGY6xPObRi2AR0IYrxI48ynNpovMvepHL5gaIndv1kaK5tPGwld S9MP0oYs9U/piKVGm4SBtMr8eXgobeMxE+mTOLYeaEg4z6RtqC7i/Hh8DcAhCWMfhxQF n1DvTHsnz5ZZnmKMgPB3todmfzHuCyBkDeDJ6AODlGgdU7rQHsgNocy8va9AijMTRzIa ajdg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition:content-transfer-encoding:in-reply-to :user-agent; bh=V5khxMwfVI0mTvPhrCOPTTSzbeth0WJ0wlwZQ8iejdk=; b=EhD+2Pst/PVe/xqDbHEopghp5G+SPu8asPQKFIXLPKny7xTdk4B4g5LWMTin1u4xgA unwXvAWrmjmiazR1wh4nNBifhpBArBhAaDpSQinkhG4RHsWZ1nsqzpqi6ZCZxn5RM1rn 8lPlEXg+2QrY/Askm6m57rHU+f8SrIU9nMM+MN0GhNIy/qflXAw15VqxekIAaqPxqcC1 R3Ed83KaG1FYPXv72w5PLUwZn3zD25ukqX+UGDJdEClWRHZ+fSq24V7qDyvHlH0XiA3X CRS+p2QLVoDuNhOX37g3Cm+vdKgA6jiCvqP/sjYznpOaF6TlQw4HDX9EfMP3umbSasN1 5l6g== X-Gm-Message-State: APjAAAWQfzPrfBX9jIifOF1jLN2C/C3J07HEcsXBygq0wkz9t7/9urem WIAi2XzQFfwMioxbdAiV2YjQ4Q== X-Google-Smtp-Source: APXvYqytxRAmE6JkYdXUbmUI4bJjASi5uAtld0aVQ4+rdHUcY+AVsPChwxu8lzIl9FmR95gW45qwAw== X-Received: by 2002:a0c:ecc9:: with SMTP id o9mr25417421qvq.100.1564970628158; Sun, 04 Aug 2019 19:03:48 -0700 (PDT) Received: from nimloth.alvh.no-ip.org ([191.125.99.87]) by smtp.gmail.com with ESMTPSA id x7sm3741383qts.38.2019.08.04.19.03.44 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Sun, 04 Aug 2019 19:03:47 -0700 (PDT) Received: by nimloth.alvh.no-ip.org (Postfix, from userid 1000) id 65046120E34; Sun, 4 Aug 2019 18:43:49 -0400 (-04) Date: Sun, 4 Aug 2019 18:43:49 -0400 From: Alvaro Herrera To: yuzuko Cc: shawn wang , Shawn Wang , PostgreSQL Hackers Subject: Re: Problem with default partition pruning Message-ID: <20190804224349.GA1366@alvherre.pgsql> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="RnlQjJ0d97Da+TV1" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: User-Agent: Mutt/1.9.4 (2018-02-28) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --RnlQjJ0d97Da+TV1 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit I propose the comment rewordings as attached. Mostly, this updates the comment atop the function to cover the case being modified, and then the new comment just refers to the new explicitly stated policy, so it bcomes simpler. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services --RnlQjJ0d97Da+TV1 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6_ignore_contradictory_where_clauses_at_partprune_step.patch" diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 09c4ed83b6..9462264e84 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -849,10 +849,11 @@ get_matching_partitions(PartitionPruneContext *context, List *pruning_steps) * the context's steps list. Each step is assigned a step identifier, unique * even across recursive calls. * - * If we find clauses that are mutually contradictory, or a pseudoconstant - * clause that contains false, we set context->contradictory to true and - * return NIL (that is, no pruning steps). Caller should consider all - * partitions as pruned in that case. + * If we find clauses that are mutually contradictory, or contradictory with + * the partitioning constraint, or a pseudoconstant clause that contains + * false, we set context->contradictory to true and return NIL (that is, no + * pruning steps). Caller should consider all partitions as pruned in that + * case. */ static List * gen_partprune_steps_internal(GeneratePruningStepsContext *context, @@ -942,35 +943,15 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, } else { + PartitionPruneStep *orstep; + /* * The arg didn't contain a clause matching this * partition key. We cannot prune using such an arg. * To indicate that to the pruning code, we must * construct a dummy PartitionPruneStepCombine whose * source_stepids is set to an empty List. - * - * However, if we can prove using constraint exclusion - * that the clause refutes the table's partition - * constraint (if it's sub-partitioned), we need not - * bother with that. That is, we effectively ignore - * this OR arm. */ - List *partconstr = context->rel->partition_qual; - PartitionPruneStep *orstep; - - if (partconstr) - { - partconstr = (List *) - expression_planner((Expr *) partconstr); - if (context->rel->relid != 1) - ChangeVarNodes((Node *) partconstr, 1, - context->rel->relid, 0); - if (predicate_refuted_by(partconstr, - list_make1(arg), - false)) - continue; - } - orstep = gen_prune_step_combine(context, NIL, PARTPRUNE_COMBINE_UNION); arg_stepids = lappend_int(arg_stepids, orstep->step_id); @@ -1047,6 +1028,28 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, bool clause_is_not_null = false; PartClauseInfo *pc = NULL; List *clause_steps = NIL; + List *partconstr = context->rel->partition_qual; + + /* + * If the clause contradicts the partition constraint, mark the + * clause as contradictory and we're done. This is particularly + * helpful to prune the default partition. + */ + if (partconstr) + { + partconstr = (List *) + expression_planner((Expr *) partconstr); + if (context->rel->relid != 1) + ChangeVarNodes((Node *) partconstr, 1, + context->rel->relid, 0); + if (predicate_refuted_by(partconstr, + list_make1(clause), + false)) + { + context->contradictory = true; + return NIL; + } + } switch (match_clause_to_partition_key(context, clause, partkey, i, diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index 2d3229fd73..6ccc91d390 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -592,6 +592,24 @@ explain (costs off) select * from rlp where a < 1 or (a > 20 and a < 25); Filter: ((a < 1) OR ((a > 20) AND (a < 25))) (5 rows) +-- where clause contradicts sub-partition's constraint +explain (costs off) select * from rlp where a = 20 or a = 40; + QUERY PLAN +---------------------------------------- + Append + -> Seq Scan on rlp4_1 + Filter: ((a = 20) OR (a = 40)) + -> Seq Scan on rlp5_default + Filter: ((a = 20) OR (a = 40)) +(5 rows) + +explain (costs off) select * from rlp3 where a = 20; /* empty */ + QUERY PLAN +-------------------------- + Result + One-Time Filter: false +(2 rows) + -- redundant clauses are eliminated explain (costs off) select * from rlp where a > 1 and a = 10; /* only default */ QUERY PLAN diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql index efdedaaeb8..a26c2f0e72 100644 --- a/src/test/regress/sql/partition_prune.sql +++ b/src/test/regress/sql/partition_prune.sql @@ -85,6 +85,10 @@ explain (costs off) select * from rlp where a = 29; explain (costs off) select * from rlp where a >= 29; explain (costs off) select * from rlp where a < 1 or (a > 20 and a < 25); +-- where clause contradicts sub-partition's constraint +explain (costs off) select * from rlp where a = 20 or a = 40; +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 */ explain (costs off) select * from rlp where a > 1 and a >=15; /* rlp3 onwards, including default */ --RnlQjJ0d97Da+TV1--