Skip to content

The columnar scan is priced 1.9x to 3.4x below the heap per unit of work, and seq_page_cost decides whether that is a defect #766

Description

@jdatcmd

Measured while re-deriving #753 (see that issue's measurement comment for the full run). The
finding there splits in two, and this is the half that belongs to pgColumnar rather than to
core.

The columnar scan cost model disagrees with itself as the projection widens

Cost per millisecond of real serial execution, same query, same 2,000,197 rows, same data, on
a 4,000,000-row 14-column table and its heap twin. Core's seqscan calibration is the reference
scale: not a claim that it is true, but it is the scale every other path in the planner is
judged against.

projection columnar cost columnar min ms cost/ms heap cost/ms heap ÷ columnar
sel 61,065 176.0 347 858 2.47x
sel, a, b 83,196 216.4 385 846 2.20x
8 columns 138,522 268.3 516 765 1.48x
* 239,001 1279.1 187 944 5.05x

Two things, and the second is the one worth an issue:

  1. The columnar scan is under-priced relative to that scale by 1.5x to 5x. A path priced
    at half what it costs wins comparisons it should lose.

  2. It is not a constant offset. The heap's cost/ms is stable across projection widths, 765
    to 944, a 1.24x spread. Columnar's runs 187 to 516, a 2.8x spread, and not
    monotonically. So the model does not merely need a multiplier; its shape in projection
    width is wrong.

The * row is the same defect at its extreme: a full-row columnar scan of this table takes
1279 ms against the heap's 167 ms, 7.6x slower, while being priced at 1.5x the heap. That
columnar loses at SELECT * is expected and fine. That the cost model says 1.5x when reality
is 7.6x is not.

Why this cannot just be corrected

The scan cost is the scale every other path comparison is judged on. Raising it toward reality
would change, at least:

So this is not a one-line recalibration, and it must not be attempted as a side effect of a
parallelism fix.

What the work is

  1. Establish whether the divergence is in the per-column decode term (A columnar scan is priced with no decode cost, so the planner declines a parallel projection that is 2.9x faster #503), the
    projected-width I/O term (Point lookup regressed 23.75 ms to 1251.88 ms once ANALYZE has run, and ANALYZE itself is pathologically slow on some shapes #171), or the base. The 2.8x spread across widths says at
    least one width-dependent term is mis-shaped, and the * outlier says the widest case is
    worst, which points at decode rather than I/O.
  2. Re-derive each term against measured time on a fixture with real entropy, at several
    projection widths and several column types (the * case here includes four md5 text
    columns and a numeric; text decode may be the whole story).
  3. Change one term at a time, with the suites above as the controls, and require
    analyze_stats and the index-path suites green at each step rather than only at the end.

What would make this closable

A cost/ms spread for columnar comparable to the heap's 1.24x across the same projection
widths, with the point-lookup and index-fetch behaviour unchanged. The absolute scale matters
less than the consistency: a model that is uniformly 2x low is a multiplier away from correct,
and one that varies 2.8x with projection width is choosing wrong plans in both directions.

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