sql 264 lines · 2 tabs

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.


Related snips

sql
-- Simple function
CREATE OR REPLACE FUNCTION get_full_name(
  first_name VARCHAR,
  last_name VARCHAR
)
RETURNS VARCHAR AS $$

Stored procedures and functions in PostgreSQL

postgresql stored-procedures functions
by Maria Garcia 2 tabs
python
import pandas as pd
from sklearn.ensemble import IsolationForest

df = pd.read_csv('service_metrics.csv')
features = df[['latency_p95', 'error_rate', 'throughput', 'cpu_utilization']]

Anomaly detection with isolation forest and robust thresholds

anomaly-detection isolation-forest monitoring
by Dr. Elena Vasquez 1 tab
sql
-- EXPLAIN ANALYZE (actual execution statistics)
EXPLAIN ANALYZE
SELECT u.username, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.created_at >= '2024-01-01'

Advanced query optimization techniques

database optimization query-performance
by Maria Garcia 2 tabs
yaml
# Grafana provisioning: datasources
# /etc/grafana/provisioning/datasources/prometheus.yml
apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus

Grafana dashboards as code with JSON provisioning

grafana dashboards monitoring
by Ryan Nakamura 2 tabs
sql
-- Publisher: Send notification
NOTIFY new_order, 'Order #12345 created';

-- Subscriber: Listen for notifications
LISTEN new_order;

PostgreSQL LISTEN/NOTIFY for pub-sub messaging

postgresql listen-notify pub-sub
by Maria Garcia 2 tabs
python
import pandas as pd

df = pd.read_csv('traffic.csv', parse_dates=['timestamp'])
df['timestamp'] = pd.to_datetime(df['timestamp'], utc=True)
df = df.set_index('timestamp').sort_index()

Time series resampling and rolling windows in pandas

pandas time-series resampling
by Dr. Elena Vasquez 1 tab

Share this code

Here's the card — post it anywhere.

Time-series data and TimescaleDB optimization — share card
Link copied