On Wed, Aug 16, 2017 at 9:23 PM, Konstantin Knizhnik
<k.knizh...@postgrespro.ru> wrote:
> postgres=# explain select * from bt where k between 1 and 20000 and v = 100;
>                               QUERY PLAN
> ----------------------------------------------------------------------
>  Append  (cost=0.29..15.63 rows=2 width=8)
>    ->  Index Scan using dti1 on dt1  (cost=0.29..8.30 rows=1 width=8)
>          Index Cond: (v = 100)
>    ->  Index Scan using dti2 on dt2  (cost=0.29..7.33 rows=1 width=8)
>          Index Cond: (v = 100)
>          Filter: (k <= 20000)
> (6 rows)

+1

This seems like a good feature to me: filtering stuff that is
obviously true is a waste of CPU cycles and may even require people to
add redundant stuff to indexes.  I was pondering something related to
this over in the partition-wise join thread (join quals that are
implied by partition constraints and should be discarded).

It'd be interesting to get Amit Langote's feedback, so I CC'd him.
I'd be surprised if he and others haven't got a plan or a patch for
this down the back of the sofa.

I might be missing some higher level architectural problems with the
patch, but for what it's worth here's some feedback after a first read
through:

--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -1441,6 +1441,20 @@ relation_excluded_by_constraints(PlannerInfo *root,
     if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo, false))
         return true;

+    /*
+     * Remove from restrictions list items implied by table constraints
+     */
+    safe_restrictions = NULL;
+    foreach(lc, rel->baserestrictinfo)
+    {
+        RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);

I think the new way to write this is "RestrictInfo *rinfo =
lfirst_node(RestrictInfo, lc)".

+        if (!predicate_implied_by(list_make1(rinfo->clause),
safe_constraints, false)) {
+            safe_restrictions = lappend(safe_restrictions, rinfo);
+        }
+    }
+    rel->baserestrictinfo = safe_restrictions;

It feels wrong to modify rel->baserestrictinfo in
relation_excluded_by_constraints().  I think there should probably be
a function with a name that more clearly indicates that it mutates its
input, and you should call that separately after
relation_excluded_by_constraints().  Something like
remove_restrictions_implied_by_constraints()?

> It is because operator_predicate_proof is not able to understand that k <
> 20001 and k <= 20000 are equivalent for integer type.
>
> [...]
>
>  /*
>   * operator_predicate_proof
>      if (clause_const->constisnull)
>          return false;
>
> +    if (!refute_it
> +        && ((pred_op == Int4LessOrEqualOperator && clause_op ==
> Int4LessOperator)
> +            || (pred_op == Int8LessOrEqualOperator && clause_op ==
> Int8LessOperator)
> +            || (pred_op == Int2LessOrEqualOperator && clause_op ==
> Int2LessOperator))
> +        && pred_const->constbyval && clause_const->constbyval
> +        && pred_const->constvalue + 1 == clause_const->constvalue)
> +    {
> +        return true;
> +    }
> +

I'm less sure about this part.  It seems like a slippery slope.

A couple of regression test failures:

     inherit                  ... FAILED
     rowsecurity              ... FAILED
========================
 2 of 179 tests failed.
========================

I didn't try to understand the rowsecurity one, but at first glance
all the differences reported in the inherit test are in fact cases
where your patch is doing the right thing and removing redundant
filters from scans.  Nice!

-- 
Thomas Munro
http://www.enterprisedb.com


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to