Stats collection for compressed chunks - #9730
Conversation
|
@kpan2034, @pnthao: please review this pull request.
|
5ef3b89 to
355039c
Compare
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
|
Hey @dbeck, not sure if you're aware (and if fit with this PR) but Postgres has Custom Cumulative Statistics for extensions since PG18 - https://wiki.postgresql.org/wiki/CustomCumulativeStats. Those custom cumulatiuve statistcs survive to restarts like any other Postgres cumulative statistic (aka pg_stat_*). |
Hey @fabriziomello , good to hear from you! Thanks for the pointer, I quickly checked and I'll look more into it. I see it has lots of bells and whistles, looks quite a bit complicated to achieve what we wanted. The support of previous versions is a concern too. I'll discuss with the team if this acceptable to only support PG18. |
dd63020 to
7c24bb7
Compare
4c525fd to
2c138c5
Compare
14b87a1 to
f6d250f
Compare
antekresic
left a comment
There was a problem hiding this comment.
Another pass, will look at this some more.
antekresic
left a comment
There was a problem hiding this comment.
Couple of nits but otherwise it lgtm!
ed9be87 to
3473922
Compare
2a8c441 to
766b6d1
Compare
This change collects information about compressed chunks and stores them in an LRU fashion. It captures events at compression, query and DML oparations. The query/DML operations maintain totals and information about the last operation. The chunk information is maintained in shared memory per database. One can access the data via calling the - `_timescaledb_functions.chunk_statistics(..)` function or by selecting from the - `timescaledb_information.stat_chunk_activity` view the former allows the user to push down filters, so it is faster and with less lock contention. The amount of shared memory is controlled by the GUC: - `timescaledb.stats_max_chunks` If the GUC is set to zero, the feature is disabled. The default value is 1024 and the maximum is 262144. The amount must be a power of two number. The `stats_max_chunks` value controls how many chunk we store information about. The memory consumption is 300 bytes per entry. If the loader is not upgraded, the statistics will be disabled on PG 15/16. PG 17 doesn't require a loader change, so we can upgrade the extension without restarting: Disable-check: loader-change Co-authored-by: Ante Kresic <antekresic@users.noreply.github.com> Signed-off-by: David Beck <dbeck@users.noreply.github.com>
## 2.28.0 (2026-06-16) This release contains performance improvements and bug fixes since the 2.27.2 release. We recommend that you upgrade at the next available opportunity. **Highlighted features in TimescaleDB v2.28.0** * **Faster `first()` and `last()` queries on compressed data.** TimescaleDB derives `first(value, time)` and `last(value, time)` aggregates straight from the columnstore's batch metadata, skipping batch decompression entirely. For the "latest reading per series" lookups that time-series workloads run constantly, that means meaningfully faster recency queries with no changes to your SQL queries. * **Lighter, less disruptive continuous aggregate refreshes.** `refresh_continuous_aggregate()` can now run incrementally in batches — the same behavior refresh policies already use — enabling breaking large manual refreshes into smaller chunks (tunable via `buckets_per_batch`, `max_batches_per_execution`, and `refresh_newest_first`) instead of one heavy operation. Refreshes also now take a lighter lock while processing the invalidation log, so they no longer block unrelated concurrent operations on the same continuous aggregate, improving behavior for concurrent workloads. * **Vectorized execution now covers `CASE` expressions.** TimescaleDB's columnar executor can now evaluate `CASE ... WHEN` expressions directly on compressed data, so queries using conditional logic stay on the fast vectorized path instead of falling back to slower row-by-row decompression. This speeds up a common pattern — conditional aggregations and computed columns over compressed history — with no query changes needed. * **Add new aggregations to a continuous aggregate without rebuilding it.** You can now run `ALTER MATERIALIZED VIEW <cagg> ADD COLUMN <name> <type> GENERATED ALWAYS AS (<aggregate>) STORED` to add a new computed aggregate to an existing continuous aggregate in place — no more dropping and recreating the whole aggregate just to track one more metric. New data populates the column going forward, letting your rollups evolve alongside your application. (Existing rows start as `NULL`; a forced refresh backfills them when you need historical values.) **Deprecation Notice: PostgreSQL 15 Support** This release marks the final minor version of TimescaleDB that will support PostgreSQL 15. Starting with our next release, version 2.29.0, we will officially drop support for Postgres 15, and only support Postgres 16, 17, and 18; however, all future patch releases within the current 2.28 version cycle will continue to fully support it. We recommend planning your PostgreSQL upgrades accordingly to ensure a smooth transition. **Deprecation Notice: `chunk_constraint` Catalog Table** Please note that the `_timescaledb_catalog.chunk_constraint` table has been dropped and temporarily replaced by a view, which introduces a change to the underlying objects while maintaining current query behavior. However, this compatibility view will be completely removed in a future release. To ensure your queries remain compatible moving forward, we strongly advise transitioning to the stable contracts provided by our [informational views](https://www.tigerdata.com/docs/reference/timescaledb/informational-views). **Backward-Incompatible Changes** * [#9934](#9934) Remove adaptive chunking **Features** * [#4054](#4054) Support `ANALYZE` and `VACUUM` on continuous aggregates by redirecting to the underlying materialization hypertable * [#9125](#9125) Increase the parallelism of `SELECT` queries over compressed hypertables to approximately match the uncompressed data size * [#9410](#9410) Mark `hypertable` and `chunk` as user catalog tables * [#9416](#9416) Support some forms of `CASE` expression in columnar aggregation and grouping * [#9580](#9580) Add `first` / `last` sparse indexes to compression * [#9784](#9784) Use `first` / `last` sparse index for `orderby` metadata on new compressed chunks * [#9668](#9668) Allow database owner to configure hypertables and policies * [#9701](#9701) Relax lock during continuous aggregate invalidation log processing * [#9730](#9730) Add in-memory observability for compressed chunks * [#9735](#9735) Improve `GapFill` row count estimate * [#9821](#9821) Allow subquery results which are exec params as GapFill arguments * [#9825](#9825) Support `ADD COLUMN` on continuous aggregates * [#9842](#9842) Suppress continuous aggregate invalidation tracking during bulk loads * [#9878](#9878) Remove `chunk_constraint` catalog tracking for foreign keys * [#9893](#9893) Remove `chunk_constraint` catalog tracking for non-dimensional constraints * [#9903](#9903) Incremental refresh for `refresh_continuous_aggregate()` * [#9915](#9915) Remove `_timescaledb_catalog.chunk_constraint` table * [#9938](#9938) Add `rebuild_sparse_index` function * [#9964](#9964) Add a function to lock OSM chunk's dimension slice * [#9980](#9980) Support `first/last(value, time)` in `ColumnarIndexScan` **Bugfixes** * [#9708](#9708) Guard time bucket parameter handling against bad input * [#9745](#9745) Check constraints when adding unique constraints to chunks * [#9890](#9890) Fix incremental refresh batch boundaries to align with variable-width buckets and start only where a chunk and an invalidation overlap * [#9914](#9914) Fix use-after-free in segmentwise recompression * [#9929](#9929) Fix background jobs being bumped in the queue forever and never running * [#9955](#9955) Fix wrong results when using Batch Sorted Merge with no first-last index on a non-leading order by column * [#9967](#9967) Block upgrade after downgrade with first/last indexes present * [#9976](#9976) Fix wrong results when comparing a date column to a `timestamptz` value * [#9977](#9977) Fix `COPY WHERE` into a hypertable with dropped columns * [#9981](#9981) Fix set-returning functions in the sort key of `ColumnarScan` * [#9982](#9982) Reject `ALTER TABLE ... INHERIT` when the parent is a hypertable * [#9984](#9984) Fix handling of `NOT VALID NOT NULL` constraint for query optimization * [#9986](#9986) Handle `MERGE WHEN NOT MATCHED BY SOURCE` on hypertables * [#9988](#9988) Fix `time_bucket_gapfill` function detection * [#10003](#10003) Block unsafe updates of unique columns on compressed chunks * [#10024](#10024) Fix `approximate_row_count` handling of Infinity * [#10025](#10025) Fix rename on compressed continuous aggregates * [#10026](#10026) Fix chunk skipping near `PG_INT64_MAX` **New Settings** * `skip_cagg_invalidation`: skip continuous aggregate invalidation tracking for DML and DDL in the current session/transaction. Off by default. * `stats_max_chunks`: set the per-database compressed chunk statistics cache capacity. Defaults to 1024 chunks; set to 0 to disable the feature. **Thanks** * @Fabian-2596 for suggesting more accurate GapFill row count estimate * @otjdiepluong for fixing spelling mistakes in timescaledb source code comments * @scimad and @Nosfistis for suggesting expanding coverage for gapfill arguments
This change collects information about compressed chunks and stores
them in an LRU fashion. It captures events at compression, query
and DML oparations. The query/DML operations maintain totals and
information about the last operation.
The chunk information is maintained in shared memory per database.
One can access the data via calling the
_timescaledb_functions.chunk_statistics(..)function or byselecting from the
timescaledb_information.stat_chunk_activityviewthe former allows the user to push down filters, so it is faster and with
less lock contention.
The amount of shared memory is controlled by the GUC:
timescaledb.stats_max_chunksIf the GUC is set to zero, the feature is disabled. The default
value is 1024 and the maximum is 262144. The amount must be a
power of two number. The
stats_max_chunksvalue controlshow many chunk we store information about. The memory consumption
is 300 bytes per entry.
If the loader is not upgraded, the statistics will be disabled on PG 15/16.
PG 17 doesn't require a loader change, so we can upgrade the extension
without restarting:
Disable-check: loader-change
Co-authored-by: Ante Kresic antekresic@users.noreply.github.com
Signed-off-by: David Beck dbeck@users.noreply.github.com