Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ disk. It never changes the values that a table returns.
| `pgcolumnar.groupagg_max_groups` | integer | `1000000` | Cap on the group count the grouped vectorized aggregate builds. Over the cap the query errors. Range 1 to INT_MAX. |
| `pgcolumnar.enable_bloom_filter` | boolean | `on` | Skip chunk groups on equality filters using per-chunk bloom filters. |
| `pgcolumnar.enable_read_stream` | boolean | `on` | Prefetch block reads with the read stream API. Effective on PostgreSQL 17 and later. |
| `pgcolumnar.enable_ungrouped_vector_agg` | boolean | `off` | Answer an ungrouped aggregate (`count`, `sum`, `avg`, `min`, `max` with no `GROUP BY`) with a batch fold over decoded vectors instead of row-at-a-time. Off by default. |
| `pgcolumnar.enable_parallel_vector_agg` | boolean | `off` | Let the ungrouped batch fold run as a parallel partial aggregate under `Gather`, each worker folding its own row groups. Requires `pgcolumnar.enable_ungrouped_vector_agg`. Off by default. |
| `pgcolumnar.enable_column_projection` | boolean | `on` | Read only the columns a query references rather than every column of the row group. |
| `pgcolumnar.enable_index_fetch_penalty` | boolean | `on` | Charge a columnar index scan for the row-group decode its per-row heap fetches force, so the planner does not treat a columnar fetch as if it were a heap page read. Set to `off` to restore the pre-1.0-alpha planner behaviour. |

### Index-only scan and projections

Expand All @@ -81,6 +85,15 @@ disk. It never changes the values that a table returns.
| `pgcolumnar.enable_unique_insert_lock` | boolean | `on` | Serialize concurrent inserts of the same unique-index key with a transaction-scoped advisory lock, so overlapping same-key inserts conflict correctly. |
| `pgcolumnar.unique_lock_buckets` | integer | `128` | Advisory-lock buckets per unique index. Bounds how many advisory locks a transaction holds per unique index. Equal keys always share a bucket; unrelated keys may share one, which only over-serializes. Range 1 to 1048576. Settable only at server start: the bucket is part of the lock tag, so backends that disagree on this value would not serialize against each other. |

### Internal settings

One setting is registered but is not a tuning knob. It is listed here because it
appears in `pg_settings` and a reader who finds it there deserves an answer.

| Setting | Type | Default | Description |
| --- | --- | --- | --- |
| `pgcolumnar.bulk_parallel_writer` | boolean | `off` | Internal. Set by `pgcolumnar.parallel_copy` loader workers so they skip the storage-row creation lock when the row already exists committed, which is what lets several atomic writers load one table at once. Marked `GUC_NOT_IN_SAMPLE`; leave it alone. Setting it by hand is safe but pointless: the skip only fires when the storage row is already committed, which is exactly when the lock guards nothing. |

## Per-table storage options

`pgcolumnar.set_options` sets the storage options of one table. The new values
Expand Down
27 changes: 19 additions & 8 deletions docs/limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,21 @@ only. The rest of the extension runs on any architecture PostgreSQL supports.
operate, but they mark the rows and do not rewrite the data. Only
`pgcolumnar.vacuum` makes the space available again.
- Point lookups are slower than heap, but much less slow than before. A fetch by
item pointer finds the group of the row. It decodes only the columns that the
executor asks for, and it keeps the decoded group for the rest of the
statement. The cost therefore no longer increases with the width of the table,
or with the position of the row in its group. Heap is still faster for a
single-row fetch. Bloom filters make an equality scan faster, because they skip
row groups. They do not help a fetch by item pointer.
item pointer finds the group of the row, and it keeps the decoded group for the
rest of the statement. The cost no longer increases with the position of the row
in its group. Heap is still faster for a single-row fetch. Bloom filters make an
equality scan faster, because they skip row groups. They do not help a fetch by
item pointer.
- **The cost of a fetch does increase with the width of the table.** There are two
causes and both are easy to meet. An index fetch decodes the columns from the
first one up to the highest-numbered column that the query reads. It does not
decode only the columns that it reads. A query that reads one late column
therefore decodes every column before it. The second cause is the size limit on
the decoded columns that the statement keeps. The columns that do not fit are
decoded again on each fetch. A table of many wide text columns meets both
conditions. One measurement shows the effect. On a table of ten text columns,
with the same rows and the same plan, a query on the first column took 975 ms.
A query on the tenth column took 194,798 ms.
- A bulk `UPDATE` or `DELETE` through an index no longer costs the number of rows
multiplied by the row group size. It still costs several times more than heap.
The reason is that each changed row is marked and written again, and not
Expand Down Expand Up @@ -237,8 +246,10 @@ row-group data, such as the metapage and the space that is reserved but not
written. These blocks count as visited, but they give no rows. The planner does
not use that figure for columnar tables.

`ANALYZE` samples the rows through the fetch path and not by block. It therefore
costs more on a columnar table than on a heap of the same size.
`ANALYZE` costs more on a columnar table than on a heap of the same size. The
sampler offers every row of every block that it visits, so the cost follows the
rows offered and not the rows kept. It reads those rows with a reader that is
restricted to one row group, and not through the fetch-by-row-number path.

`TABLESAMPLE` is unsupported and says so: it raises an error rather than
returning no rows.
Expand Down
Loading