Time-series data and TimescaleDB optimization

Maria Garcia Feb 2026
2 tabs
-- Install TimescaleDB extension
CREATE EXTENSION IF NOT EXISTS timescaledb;

-- Create regular table
CREATE TABLE sensor_data (
  time TIMESTAMPTZ NOT NULL,
  sensor_id INT NOT NULL,
  temperature DOUBLE PRECISION,
  humidity DOUBLE PRECISION,
  pressure DOUBLE PRECISION
);

-- Convert to hypertable (time-series optimized)
SELECT create_hypertable('sensor_data', 'time');

-- Hypertable automatically partitions by time
-- Default: 7-day chunks

-- Create hypertable with custom chunk interval
SELECT create_hypertable(
  'sensor_data',
  'time',
  chunk_time_interval => INTERVAL '1 day'
);

-- Create index on sensor_id
CREATE INDEX idx_sensor_data_sensor_id_time
  ON sensor_data (sensor_id, time DESC);

-- Insert time-series data
INSERT INTO sensor_data VALUES
  ('2024-01-15 10:00:00', 1, 22.5, 45.2, 1013.25),
  ('2024-01-15 10:05:00', 1, 22.7, 45.0, 1013.30),
  ('2024-01-15 10:00:00', 2, 21.8, 48.5, 1012.90);

-- Time-bucketing queries
SELECT
  time_bucket('15 minutes', time) AS bucket,
  sensor_id,
  AVG(temperature) AS avg_temp,
  MAX(temperature) AS max_temp,
  MIN(temperature) AS min_temp,
  COUNT(*) AS readings
FROM sensor_data
WHERE time >= NOW() - INTERVAL '1 day'
GROUP BY bucket, sensor_id
ORDER BY bucket DESC, sensor_id;

-- Time-bucket with GAPFILL
SELECT
  time_bucket_gapfill('1 hour', time) AS hour,
  sensor_id,
  AVG(temperature) AS avg_temp,
  LOCF(AVG(temperature)) AS filled_temp  -- Last observation carried forward
FROM sensor_data
WHERE time >= NOW() - INTERVAL '7 days'
GROUP BY hour, sensor_id
ORDER BY hour DESC, sensor_id;

-- Continuous aggregates (materialized views for time-series)
CREATE MATERIALIZED VIEW sensor_data_hourly
WITH (timescaledb.continuous) AS
SELECT
  time_bucket('1 hour', time) AS hour,
  sensor_id,
  AVG(temperature) AS avg_temperature,
  MAX(temperature) AS max_temperature,
  MIN(temperature) AS min_temperature,
  AVG(humidity) AS avg_humidity,
  COUNT(*) AS reading_count
FROM sensor_data
GROUP BY hour, sensor_id;

-- Refresh continuous aggregate
CALL refresh_continuous_aggregate('sensor_data_hourly', NULL, NULL);

-- Automatic refresh policy
SELECT add_continuous_aggregate_policy(
  'sensor_data_hourly',
  start_offset => INTERVAL '3 hours',
  end_offset => INTERVAL '1 hour',
  schedule_interval => INTERVAL '1 hour'
);

-- Compression (saves 90%+ storage)
ALTER TABLE sensor_data SET (
  timescaledb.compress,
  timescaledb.compress_segmentby = 'sensor_id',
  timescaledb.compress_orderby = 'time DESC'
);

-- Add compression policy (compress data older than 7 days)
SELECT add_compression_policy(
  'sensor_data',
  INTERVAL '7 days'
);

-- Manual compression
SELECT compress_chunk(c.chunk_name)
FROM timescaledb_information.chunks c
WHERE c.hypertable_name = 'sensor_data'
  AND c.range_end < NOW() - INTERVAL '7 days';

-- Data retention policy (auto-delete old data)
SELECT add_retention_policy(
  'sensor_data',
  INTERVAL '90 days'
);

-- View chunks
SELECT * FROM timescaledb_information.chunks
WHERE hypertable_name = 'sensor_data'
ORDER BY range_start DESC;

-- Chunk statistics
SELECT
  chunk_name,
  pg_size_pretty(total_bytes) AS size,
  pg_size_pretty(compressed_total_bytes) AS compressed_size,
  ROUND(100.0 * compressed_total_bytes / NULLIF(total_bytes, 0), 2) AS compression_ratio
FROM timescaledb_information.compressed_chunk_stats
WHERE hypertable_name = 'sensor_data';
2 files · sql Explain with highlit

Time-series data tracks measurements over time—metrics, logs, sensor data. I use TimescaleDB for time-series workloads. Hypertables automatically partition by time. Continuous aggregates precompute rollups. Time-based retention policies auto-delete old data. Compression saves 90%+ storage. Time-bucketing groups data by intervals. Gap-filling handles missing data points. Understanding time-series patterns enables efficient queries. Downsampling reduces data granularity. Time-weighted averages handle irregular intervals. Proper time-series design prevents table bloat. Time-series databases outperform general RDBMS for temporal workloads. Essential for metrics, IoT, monitoring, financial data.