Rostislav Opocensky <[EMAIL PROTECTED]> writes:
> On Tue, 30 May 2000, Tom Lane wrote:
>> The problem here is that the optimizer will only consider an indexscan
>> for a clause that looks like index_key OP constant.  It doesn't think

> I'll consider having my index function return a `date'.  Still one thing
> remains unclear to me: why the optimizer doesn't use an indexscan in the
> stored procedure I have attached to my previous post.  The condition looks
> like WHERE trunc_to_day(timestamp) BETWEEN var1 AND var2.  var1 and var2
> get their values from calling the `volatile' function trunc_to_day, but
> from then on, their values can't be changed during the execution of the
> query.  Is it possible to give the optimizer a hint about it?

Hmm, actually the optimizer should/does regard those as constants within
subsequent queries (internally they are Params instead of Consts, but
that's supposed to be OK).  What I find here is that the optimizer does
consider an indexscan for this query, but there's a bug in its
selectivity estimation routine that causes it not to recognize the
BETWEEN clause as being a range restriction --- and that means it
produces a fairly high cost estimate for the indexscan.  I still got
an indexscan plan for a small test table, but on a larger table you
might not get one.

I've applied the attached patch for 7.0.1 --- if you are in a hurry,
you may care to apply it to your local copy.  It just tweaks the range-
query recognizer to accept Param as well as Const nodes.

                        regards, tom lane


*** src/backend/optimizer/path/clausesel.c.orig Tue May 30 00:26:44 2000
--- src/backend/optimizer/path/clausesel.c      Wed May 31 11:38:53 2000
***************
*** 120,129 ****
                Selectivity s2;
  
                /*
!                * See if it looks like a restriction clause with a constant. (If
!                * it's not a constant we can't really trust the selectivity!) NB:
!                * for consistency of results, this fragment of code had better
!                * match what clause_selectivity() would do.
                 */
                if (varRelid != 0 || NumRelids(clause) == 1)
                {
--- 120,131 ----
                Selectivity s2;
  
                /*
!                * See if it looks like a restriction clause with a Const or Param
!                * on one side.  (Anything more complicated than that might not
!                * behave in the simple way we are expecting.)
!                *
!                * NB: for consistency of results, this fragment of code had better
!                * match what clause_selectivity() would do in the cases it handles.
                 */
                if (varRelid != 0 || NumRelids(clause) == 1)
                {
***************
*** 134,174 ****
  
                        get_relattval(clause, varRelid,
                                                  &relidx, &attno, &constval, &flag);
!                       if (relidx != 0 && (flag & SEL_CONSTANT))
                        {
                                /* if get_relattval succeeded, it must be an opclause 
*/
!                               Oid                     opno = ((Oper *) ((Expr *) 
clause)->oper)->opno;
!                               RegProcedure oprrest = get_oprrest(opno);
  
!                               if (!oprrest)
!                                       s2 = (Selectivity) 0.5;
!                               else
!                                       s2 = restriction_selectivity(oprrest, opno,
!                                                                                      
          getrelid(relidx,
!                                                                                      
                           root->rtable),
!                                                                                      
          attno,
!                                                                                      
          constval, flag);
! 
!                               /*
!                                * If we reach here, we have computed the same result 
that
!                                * clause_selectivity would, so we can just use s2 if 
it's
!                                * the wrong oprrest.  But if it's the right oprrest, 
add
!                                * the clause to rqlist for later processing.
!                                */
!                               switch (oprrest)
                                {
!                                       case F_SCALARLTSEL:
!                                               addRangeClause(&rqlist, clause, flag, 
true, s2);
!                                               break;
!                                       case F_SCALARGTSEL:
!                                               addRangeClause(&rqlist, clause, flag, 
false, s2);
!                                               break;
!                                       default:
!                                               /* Just merge the selectivity in 
generically */
!                                               s1 = s1 * s2;
!                                               break;
                                }
-                               continue;               /* drop to loop bottom */
                        }
                }
                /* Not the right form, so treat it generically. */
--- 136,183 ----
  
                        get_relattval(clause, varRelid,
                                                  &relidx, &attno, &constval, &flag);
!                       if (relidx != 0)
                        {
                                /* if get_relattval succeeded, it must be an opclause 
*/
!                               Var                *other;
  
!                               other = (flag & SEL_RIGHT) ? get_rightop((Expr *) 
clause) :
!                                       get_leftop((Expr *) clause);
!                               if (IsA(other, Const) || IsA(other, Param))
                                {
!                                       Oid             opno = ((Oper *) ((Expr *) 
clause)->oper)->opno;
!                                       RegProcedure oprrest = get_oprrest(opno);
! 
!                                       if (!oprrest)
!                                               s2 = (Selectivity) 0.5;
!                                       else
!                                               s2 = restriction_selectivity(oprrest, 
opno,
!                                                                                      
                  getrelid(relidx,
!                                                                                      
                                   root->rtable),
!                                                                                      
                  attno,
!                                                                                      
                  constval, flag);
! 
!                                       /*
!                                        * If we reach here, we have computed the same 
result that
!                                        * clause_selectivity would, so we can just 
use s2 if it's
!                                        * the wrong oprrest.  But if it's the right 
oprrest, add
!                                        * the clause to rqlist for later processing.
!                                        */
!                                       switch (oprrest)
!                                       {
!                                               case F_SCALARLTSEL:
!                                                       addRangeClause(&rqlist, 
clause, flag, true, s2);
!                                                       break;
!                                               case F_SCALARGTSEL:
!                                                       addRangeClause(&rqlist, 
clause, flag, false, s2);
!                                                       break;
!                                               default:
!                                                       /* Just merge the selectivity 
in generically */
!                                                       s1 = s1 * s2;
!                                                       break;
!                                       }
!                                       continue;       /* drop to loop bottom */
                                }
                        }
                }
                /* Not the right form, so treat it generically. */

Reply via email to