TimescaleDB Hypertable chunk_time_interval Sizing (The 25% RAM Rule)
TimescaleOps deterministic guide to sizing TimescaleDB hypertable chunk_time_interval (1h, 6h, 1d, 7d) so active B-tree indexes stay under 25% of DDR5 RAM.
Per official TimescaleDB partitioning documentation, hypertable insert throughput stalls into random NVMe page evictions once active chunk B-tree indexes spill beyond PostgreSQL shared_buffers. On TimescaleOps, we apply the 25% DDR5 RAM budget equation to pick 7d, 1d, 6h, or 1h chunk intervals deterministically.
| Telemetry Scale | Chunk / Partition Interval | Server DDR5 RAM | Retained Disk Footprint | Matched Infrastructure Tier |
|---|---|---|---|---|
| 1K metrics/s (86M/day) | 7d (INTERVAL 7 days) |
8 GB DDR5 | ~38 GB / yr | Hostinger KVM 2 (8GB) |
| 10K metrics/s (864M/day) | 1d (INTERVAL 1 day) |
16 GB DDR5 | ~365 GB / yr | InterServer KVM 16GB / Hostinger KVM 4 |
| 50K metrics/s (4.3B/day) | 6h (INTERVAL 6 hours) |
32 GB DDR5 | ~1.82 TB / yr | InterServer Ryzen Storage / UltaHost VDS |
| 500K metrics/s (43B/day) | 1h (INTERVAL 1 hour) |
128 GB DDR5 | ~18.1 TB / yr | InterServer Bare-Metal 128GB + 20TB ZFS |
-- Audit uncompressed hypertable chunk index sizes against 25% of system RAM
SELECT
chunk_schema || '.' || chunk_name AS chunk,
pg_size_pretty(index_bytes) AS btree_index_size,
pg_size_pretty(table_bytes) AS heap_size,
is_compressed
FROM chunks_detailed_size('fleet_grid_telemetry')
ORDER BY chunk_name DESC
LIMIT 8;
-- Update future chunk_time_interval online without rewriting closed chunks
SELECT set_chunk_time_interval('fleet_grid_telemetry', INTERVAL '6 hours');
1. Why PostgreSQL Hypertable B-Tree Splits Stall Ingestion Above 25% RAM
Every row inserted into an uncompressed TimescaleDB hypertable updates composite indexes such as (asset_id, ts DESC). While timestamps advance monotonically, random device or symbol keys touch leaf pages scattered across the entire active chunk index. Keeping all open chunk indexes inside 25% of system RAM (matching PostgreSQL shared_buffers) preserves in-memory page hits instead of triggering synchronous NVMe read-modify-write stalls.
2. Avoiding Hypertable Micro-Chunk Catalog Bloat on TimescaleOps
Over-partitioning is just as harmful as oversized chunks. Setting a 5-minute chunk_time_interval on a modest 1K/s sensor stream generates 105,120 chunks per year and bloats pg_catalog lock tables during query planning. Our TimescaleOps chunk selector always picks the widest interval (7d -> 1d -> 6h -> 1h) that fits below your 25% RAM ceiling and closes ahead of add_compression_policy.
3. Accounting for Late-Arriving Cellular Backfills Across Adjacent Hypertable Chunks
When remote LTE gateways flush buffered sensor batches across a midnight boundary, two adjacent TimescaleDB chunks remain active in memory at once. We multiply single-chunk index bytes by a 1.25x to 1.85x residency factor so rollover windows stay inside RAM.
TimescaleOps Engineering Q&A: TS-01 // CHUNK-25RAM Hypertable Operations
Does changing TimescaleDB set_chunk_time_interval rewrite existing historical hypertable chunks?
No. Executing set_chunk_time_interval in TimescaleDB only governs newly created future chunks, making it safe to run online without locking or rewriting historical partitions.
Do compressed TimescaleDB hypertable chunks count toward the 25% RAM index budget?
Minimal overhead only. Once TimescaleDB converts a closed chunk into 1,000-row columnar batches, row-level B-tree indexes are dropped in favor of compact segmentby min/max metadata.
What should shared_buffers be set to on a dedicated TimescaleDB VPS?
We follow timescaledb-tune guidance by setting shared_buffers = 25% of total DDR5 RAM, leaving roughly 70% of memory for the Linux page cache, decompression work_mem, and WAL buffers.