Thread

  1. Re: Regression: partial index with IS NOT NULL predicate not used for min/max optimization on NOT NULL columns

    Tom Lane <tgl@sss.pgh.pa.us> — 2025-12-24T17:13:54Z

    Dmytro Astapov <dastapov@gmail.com> writes:
    > When a column is defined as "NOT NULL" and a partial index exists with a
    > predicate "WHERE column IS NOT NULL", the min/max aggregate optimization
    > fails to use the partial index. This is a regression introduced in
    > PostgreSQL 17.
    
    Ugh.
    
    > *Suggested fix*
    > I think that when clause in the query matches a predicate in the partial
    > index, it should not be discarded.
    
    I don't like that proposal a bit.  It makes the behavior more complex
    and less consistent, and probably re-introduces the problem complained
    of in bug #17540.
    
    The real problem here is that the operations are being done in the
    wrong order; in particular making add_base_clause_to_rel responsible
    for discarding qual conditions was a bad idea.  There are at least
    two ways we could make it work less poorly:
    
    1. postpone discarding of constant NOT NULL conditions till after
    we check index predicates;
    
    2. move discarding of constant NOT NULL conditions into
    eval_const_expressions, which can fix the problem because that
    is also applied to index predicates.
    
    I think #2 is the better answer ... and, as it happens, that got done
    recently (in e2debb643).  So HEAD no longer exhibits the problem you
    show:
    
    regression=# EXPLAIN SELECT max(seqno) FROM test;
                                                      QUERY PLAN                                                   
    ---------------------------------------------------------------------------------------------------------------
     Result  (cost=0.32..0.33 rows=1 width=4)
       Replaces: MinMaxAggregate
       InitPlan minmax_1
         ->  Limit  (cost=0.29..0.32 rows=1 width=4)
               ->  Index Only Scan Backward using test_seqno_idx on test  (cost=0.29..3050.29 rows=100000 width=4)
    (5 rows)
    
    However, there is still a check for constant-true conditions
    in add_base_clause_to_rel, because the author argued that there
    are edge cases that still justify it.  I am wondering though if
    your example can be modified so that it still misbehaves in HEAD.
    That would be ammunition to remove the check altogether, which
    I still think is what we should do.  It's a fundamental structural
    error to do this there.
    
    			regards, tom lane