diff --git a/docs/configuration.md b/docs/configuration.md index bf66ac4..fc9542e 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -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 @@ -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 diff --git a/docs/limitations.md b/docs/limitations.md index f618b2c..96e6615 100644 --- a/docs/limitations.md +++ b/docs/limitations.md @@ -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 @@ -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.