Skip to content

We have no join-heavy benchmark, and no columnar-specific join optimisation; measure before deciding on set_join_pathlist_hook #401

Description

@ChronicallyJD

Our optimisations stop at the scan and the aggregate directly above it. A join is core's
node, and we get no say in join order, join method, or what reaches the columnar side.

Confirmed structurally: we install set_rel_pathlist_hook, create_upper_paths_hook,
build_simple_rel_hook (get_relation_info_hook below 19), object_access_hook and
ProcessUtility_hook. There is no set_join_pathlist_hook, so we never offer a join
path.

Measured, a columnar-to-heap join today:

 Finalize GroupAggregate
   ->  Gather Merge  (Workers Planned: 6)
         ->  Partial HashAggregate
               ->  Hash Join
                     Hash Cond: (c.hostname = d.hostname)
                     ->  Parallel Custom Scan (ColumnarScan) on cpu_pgc c
                     ->  Hash -> Seq Scan on hosts_dim d

That works, and it works because we are a table access method rather than a foreign data
wrapper. Cross-format joins have never needed anything from us.

First, what this is not

It will not help the cross-engine numbers. All eight TSBS queries in
docs/benchmarks.md are single-table:

$ grep -lciE '\bjoin\b' queries/tsbs/*.sql | wc -l
0
$ grep -hiE '^\s*FROM' queries/tsbs/*.sql | sort | uniq -c
      8 FROM %T

There is no join in that benchmark to accelerate. Anyone reaching for this as a way to
close the TimescaleDB gap should reach for the clustering result instead, which is
measured and large.

The actual gap, which is a measurement gap

We have never measured a join-heavy workload on pgColumnar. Our whole performance story
is single-table scans and aggregates, which is the shape TSBS has. Star schemas and
dimension joins are the shape columnar storage is usually bought for, and we do not know
what we do on them. Not "we know and it is bad" -- we do not know.

That is the prerequisite. Proposing a join implementation before measuring whether we lose,
and where, is committing to work with no evidence behind it.

The mechanism worth evaluating, which is not join ordering

If there is a win available inside a table access method, the literature says it is
runtime filter pushdown, not join order. When the build side of a hash join produces a
small key set, pushing that set into the probe side's scan lets it skip data before
decoding it.

We are unusually well placed for this. The scan already skips chunk groups on zone maps and
already does equality skipping through pgcolumnar.enable_bloom_filter. What is missing is
a way to hand it a key set discovered at runtime rather than one written in the query.

Whether PostgreSQL's executor lets an extension do that cleanly is exactly the unknown.

Suggested sequence

  1. Build a join-heavy fixture and measure it. A star schema: one columnar fact table,
    several heap dimensions, and the ordinary selective-dimension-join shape. Compare against
    heap and against TimescaleDB, the same way the cross-engine page does, and publish the
    result whichever way it goes.
  2. Read the plans, not just the timings. The question is where the time goes: decoding
    rows the join then discards, or the join itself. Those lead to different work, and the
    chunk-group counters already tell us which.
  3. Only then decide whether runtime filter pushdown is reachable, and only then whether
    set_join_pathlist_hook is needed for it.

Step 1 is worth doing on its own merits regardless of what follows, because a columnar
extension with no join benchmark has a hole in its evidence.

Related

design/ROADMAP.md carries this as an open question, "which join-acceleration technique
returns the most inside a table access method, and how does it interact with the planner
and executor hooks". This issue is that question with the measurement step in front of it.
See also #395: that question living only in a design document is why it has sat unexamined.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions