Re: Batching in executor

From: Denis Smirnov <darthunix(at)gmail(dot)com>
To: Erik Nordström <erik(at)tigerdata(dot)com>
Cc: Amit Langote <amitlangote09(at)gmail(dot)com>, Antonin Houska <ah(at)cybertec(dot)at>, Junwang Zhao <zhjwpku(at)gmail(dot)com>, cca5507 <cca5507(at)qq(dot)com>, Daniil Davydov <3danissimo(at)gmail(dot)com>, PostgreSQL-development <pgsql-hackers(at)postgresql(dot)org>, Tomas Vondra <tomas(at)vondra(dot)me>, Mats Kindahl <mats(dot)kindahl(at)gmail(dot)com>
Subject: Re: Batching in executor
Date: 2026-08-15 09:08:18
Message-ID: 85371DE4-6957-4408-9FAA-A4871B501AB6@gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi Erik,

Thank you. Your slot-based design is very close to the direction I think we
should take.

The idea is to generalize tts_batch for both heap and columnar storage. We
do not want to add a new table AM callback. A batch should keep its native
data for as long as possible. For heap, this would be an array of Datum
values for each column, built from a pinned buffer page. A columnar slot
could keep Arrow arrays, compressed columns, dictionaries, or any other
extension-specific data. Conversion to Datum would happen only when a
regular PostgreSQL node asks for rows.

The structures could look roughly like this:

typedef struct TupleBatchRequest
{
Bitmapset *filter_attrs;
Bitmapset *output_attrs;
} TupleBatchRequest;

typedef struct TupleTableSlotBatch
{
const TupleTableSlotBatchOps *ops;
void *private_data;
const TupleBatchRequest *request;

/*
* One bit per row. A set bit means that the row passed the filters.
* NULL means that all rows passed.
*/
const uint64 *selection;

uint64 generation;
int ntuples;
int current;
} TupleTableSlotBatch;

TupleBatchRequest would be set in the scan slot during initialization. The
separate attribute sets allow the slot to prepare filter columns first.
After filtering, it can prepare output columns only if some rows passed.

The ops identify the native batch layout. They also provide a way to convert
the needed data to Datum and a way to mark the batch as consumed.

ExecProcNode() would remain the only interface between plan nodes. Existing
nodes would ignore tts_batch and continue to read the current row through
the normal slot API.

A batch-aware node would call ExecProcNode() in the same way, then inspect
slot->tts_batch. If it understands the batch ops, it can process all
remaining selected rows at once. Otherwise, it uses the normal row path.

A simple projection could keep the batch and only remap column numbers. A
complex projection would switch to the normal Datum row path.

A batch-aware Agg could read the selection bitmap and native columns
directly. It could add an aggregate FILTER mask and process the whole batch.
Unsupported aggregates or batch layouts would use the existing row path.
The final aggregate values would still be returned as normal Datum values.

After processing a batch, the parent must mark it as consumed. The next
ExecProcNode() call would then read the next batch. This step must also
update executor statistics. The scan node counts rows rejected by filters,
and a helper such as

ExecConsumeSlotBatch(child, slot, nconsumed)

could account for all rows processed by one ExecProcNode() call.

This also seems to fit current TimescaleDB well. DecompressBatchState could
be stored in private_data. total_batch_rows, next_batch_row, and
vector_qual_result map directly to the common batch fields.
CompressedColumnValues can stay in the native TimescaleDB format.
compressed_batch_discard_tuples() already works like the consume operation.

ColumnarScan could return this slot through its normal ExecProcNode().
VectorAgg could detect the batch and process it directly, without bypassing
ColumnarScan and reading its child.

Does this match what you would want ColumnarScan to expose?

Best regards,
Denis Smirnov

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Fujii Masao 2026-08-15 09:14:38 Re: Rename EXISTS-to-ANY converted subplan to exists_to_any
Previous Message Daniel Gustafsson 2026-08-15 08:58:53 Re: basebackup: do not verify checksums on pages written before enabling checksums