Skip to content

PostgreSQL 18: disabled_nodes and disable_cost #223

@michaelpq

Description

@michaelpq

Commit e22253467942 introduced in PostgreSQL 18 is at the origin of a few incorrect things in the module:
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=e22253467

Treat number of disabled nodes in a path as a separate cost metric.

Previously, when a path type was disabled by e.g. enable_seqscan=false,
we either avoided generating that path type in the first place, or
more commonly, we added a large constant, called disable_cost, to the
estimated startup cost of that path. This latter approach can distort
planning. For instance, an extremely expensive non-disabled path
could seem to be worse than a disabled path, especially if the full
cost of that path node need not be paid (e.g. due to a Limit).
Or, as in the regression test whose expected output changes with this
commit, the addition of disable_cost can make two paths that would
normally be distinguishible in cost seem to have fuzzily the same cost.

So the root of the idea is that we should not rely any more on disable_cost to disable entirely a path, but update disable_nodes to do this job. This impacts the following code paths in pg_hint_plan.c, where we force or unforce the use of some paths:

$ git grep -e "startup_cost" -e "total_cost" 
pg_hint_plan.c:             if (path->startup_cost < disable_cost)
pg_hint_plan.c:                 path->startup_cost += disable_cost;
pg_hint_plan.c:                 path->total_cost += disable_cost;
pg_hint_plan.c:                         ppath->startup_cost = 0;
pg_hint_plan.c:                         ppath->total_cost = 0;
pg_hint_plan.c:                     if (ppath->startup_cost < disable_cost)
pg_hint_plan.c:                         ppath->startup_cost += disable_cost;
pg_hint_plan.c:                         ppath->total_cost += disable_cost;
pg_hint_plan.c:                 path->startup_cost = 0;
pg_hint_plan.c:                 path->total_cost = 0;

I have analyzed most of the regression tests, and I think that we should be "mostly" fine with a refresh of the EXPLAIN plans where we have nodes marked as "Disabled" by the planner but we finish by using them. The solution is I think something close to that:

  • When we want to force a path to be used, let the costs at 0, set disabled_nodes at 0.
  • When we want to disable a path, disable_cost does not need to be used anymore, we can just increment disabled_nodes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions