Re: Optimizer hook - Mailing list pgsql-patches

From Julius Stroffek
Subject Re: Optimizer hook
Date
Msg-id 46F9893F.5070300@sun.com
Whole thread Raw
In response to Re: Optimizer hook  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: Optimizer hook
List pgsql-patches
Well, It seems that I probably do not understand something quite well or
my explanation
is not clear. There is some example code of my idea in the attachment.

There is a function jos_search which has nearly the same code as
make_rel_from_joinlist.
The example tries geqo first and then the regular algorithm. At the
first sight it seems that
it is possible to do the same with the hook placed to the current
decision point. However,
the execution flow is slightly different.

1.) example in dummy.c
---
It first uses geqo only to find the cheapest path also for all the recursive
calls in jos_search. Afterwards, the same is executed using the regular
algorithm
also for all the recursive calls in jos_search. The whole result path
for the query
will be produced only by either geqo or regular algorithm.

2.) placing the hook to the current decision point and trying both
geqo®ular
at that place.
---
Parts of the result path might be found by geqo and parts of it by
regular algorithm.

The problem here is that regular algorithm will find the best plan every
time it finishes. However, the above is supposed to be used for the
algorithms
that none of them is supposed to find the best solution.

> That would be an entirely different problem, I think.  If you want to
> replace the *entire* planner, there's already the planner_hook to do that.
>
Replacing the whole planner would need a much more code to be reused without
any change than in this case.

> you can't just willy-nilly replace the code for
> single-relation path selection, at least not without a whole lot of
> changes elsewhere in the planner infrastructure.
>
Would the code in dummy.c work in a way that I expect and explained above?
If there is no way of how to make the code work then it makes no sense
to put the hook to the place I am proposing. It works for me, but I have
not tested that very well yet. If I would swap calls to geqo
and make_one_rel_by_joins it will not work. Therefore there might be
an issue I do not know about yet.
> My thought was that the reason for this hook to exist was simply to
> provide a convenient way to replace only the join search order
> algorithm.
Yes, thats true. I do not have a plan to do something more for now.

Thank you

Regards

Julius Stroffek

#include "postgres.h"

#include "fmgr.h"
#include "optimizer/geqo.h"
#include "optimizer/paths.h"
#include "optimizer/pathnode.h"


PG_MODULE_MAGIC;

void    _PG_init(void);
void    _PG_fini(void);

typedef RelOptInfo * (*jos_function_type) (PlannerInfo *root, int levels_needed, List* initial_rels);

static
RelOptInfo *
jos_search(PlannerInfo *root, List *joinlist, jos_function_type jos_function)
{
     int         levels_needed;
     List       *initial_rels;
     ListCell   *jl;

     /*
      * Count the number of child joinlist nodes.  This is the depth of the
      * dynamic-programming algorithm we must employ to consider all ways of
      * joining the child nodes.
      */
     levels_needed = list_length(joinlist);

     if (levels_needed <= 0)
         return NULL;            /* nothing to do? */

     /*
      * Construct a list of rels corresponding to the child joinlist nodes.
      * This may contain both base rels and rels constructed according to
      * sub-joinlists.
      */
     initial_rels = NIL;
     foreach(jl, joinlist)
     {
         Node       *jlnode = (Node *) lfirst(jl);
         RelOptInfo *thisrel;

         if (IsA(jlnode, RangeTblRef))
         {
             int         varno = ((RangeTblRef *) jlnode)->rtindex;

             thisrel = find_base_rel(root, varno);
         }
         else if (IsA(jlnode, List))
         {
             /* Recurse to handle subproblem */
             thisrel = jos_search(root, (List *) jlnode, jos_function);
         }
         else
         {
             elog(ERROR, "unrecognized joinlist node type: %d",
                  (int) nodeTag(jlnode));
             thisrel = NULL;     /* keep compiler quiet */
         }

         initial_rels = lappend(initial_rels, thisrel);
     }

     if (levels_needed == 1)
     {
         /*
          * Single joinlist node, so we're done.
          */
         return (RelOptInfo *) linitial(initial_rels);
     }
     else
     {
         jos_function(root, levels_needed, initial_rels);
     }
}


static
RelOptInfo *
jos_dummy(PlannerInfo *root, List *joinlist)
{
    RelOptInfo *dynamic_result, *geqo_result;
    List *copy;
    Cost dynamic_cost, geqo_cost;

    copy = list_copy(joinlist);
    elog(LOG, "Starting a join order search \"geqo\"...");
    geqo_result = jos_search(root, copy, geqo);
//    geqo_result = jos_search(root, copy, make_one_rel_by_joins);
    geqo_cost = geqo_result->cheapest_total_path->total_cost;

    copy = list_copy(joinlist);
    elog(LOG, "Starting a join order search \"dynamic\"...");
    dynamic_result = jos_search(root, copy, make_one_rel_by_joins);
//    dynamic_result = jos_search(root, copy, geqo);
    dynamic_cost = dynamic_result->cheapest_total_path->total_cost;


    printf("GEQO cost: %f\n", geqo_cost);
    printf("Dynamic programming cost: %f\n", dynamic_cost);

    if (geqo_cost < dynamic_cost)
        return geqo_result;
    else
        return dynamic_result;
}


void
_PG_init(void)
{
    join_order_search_hook = jos_dummy;
}

void
_PG_fini(void)
{
    join_order_search_hook = 0;
}


pgsql-patches by date:

Previous
From: Tom Lane
Date:
Subject: Re: Optimizer hook
Next
From: Tom Lane
Date:
Subject: Re: Optimizer hook