Что такое TimescaleDB?

TimescaleDB — это специализированная база данных временных рядов (time-series), построенная как расширение PostgreSQL. Она объединяет масштабируемость NoSQL систем с привычностью и надёжностью SQL, оптимизированная для работы с временными данными.

Ключевые особенности TimescaleDB

  • Полная SQL совместимость — все возможности PostgreSQL
  • Автоматическое партицирование — по времени и пространству
  • Hypertables — абстракция над партицированными таблицами
  • Непрерывные агрегаты — предвычисленные представления
  • Сжатие данных — экономия места на диске
  • Политики хранения — автоматическое удаление старых данных

Установка TimescaleDB

Установка на Ubuntu/Debian:

 1# Добавление репозитория TimescaleDB
 2echo "deb https://packagecloud.io/timescale/timescaledb/ubuntu/ $(lsb_release -c -s) main" | sudo tee /etc/apt/sources.list.d/timescaledb.list
 3wget --quiet -O - https://packagecloud.io/timescale/timescaledb/gpgkey | sudo apt-key add -
 4
 5# Установка
 6sudo apt-get update
 7sudo apt-get install timescaledb-2-postgresql-14
 8
 9# Настройка PostgreSQL
10sudo timescaledb-tune
11sudo systemctl restart postgresql
12
13# Создание расширения в базе данных
14psql -d mydb -c "CREATE EXTENSION IF NOT EXISTS timescaledb;"

Установка через pip для разработки:

1# Установка клиентских библиотек
2pip install psycopg2-binary
3
4# Для работы с аналитикой
5poetry add psycopg2-binary pandas matplotlib

Создание hypertable

 1-- Создание обычной таблицы
 2CREATE TABLE sensor_data (
 3    time TIMESTAMPTZ NOT NULL,
 4    sensor_id INTEGER,
 5    temperature DOUBLE PRECISION,
 6    humidity DOUBLE PRECISION,
 7    location TEXT
 8);
 9
10-- Преобразование в hypertable
11SELECT create_hypertable('sensor_data', 'time');
12
13-- Создание индексов для лучшей производительности
14CREATE INDEX ON sensor_data (sensor_id, time DESC);
15CREATE INDEX ON sensor_data (location, time DESC);

Работа с данными временных рядов

 1-- Вставка данных
 2INSERT INTO sensor_data (time, sensor_id, temperature, humidity, location)
 3VALUES 
 4    (NOW(), 1, 22.5, 65.2, 'office'),
 5    (NOW() - INTERVAL '1 minute', 1, 22.3, 65.5, 'office'),
 6    (NOW() - INTERVAL '2 minutes', 2, 21.8, 64.1, 'warehouse');
 7
 8-- Запросы с временными функциями
 9SELECT 
10    time_bucket('1 hour', time) AS hour,
11    sensor_id,
12    AVG(temperature) as avg_temp,
13    MAX(temperature) as max_temp,
14    MIN(temperature) as min_temp
15FROM sensor_data 
16WHERE time >= NOW() - INTERVAL '1 day'
17GROUP BY hour, sensor_id
18ORDER BY hour DESC;
19
20-- Поиск аномалий
21SELECT time, sensor_id, temperature
22FROM sensor_data
23WHERE temperature > (
24    SELECT AVG(temperature) + 2 * STDDEV(temperature)
25    FROM sensor_data
26    WHERE time >= NOW() - INTERVAL '1 hour'
27);

Непрерывные агрегаты

 1-- Создание непрерывного агрегата для почасовой статистики
 2CREATE MATERIALIZED VIEW hourly_stats
 3WITH (timescaledb.continuous) AS
 4SELECT 
 5    time_bucket('1 hour', time) AS hour,
 6    sensor_id,
 7    AVG(temperature) as avg_temp,
 8    MAX(temperature) as max_temp,
 9    MIN(temperature) as min_temp,
10    COUNT(*) as readings_count
11FROM sensor_data
12GROUP BY hour, sensor_id;
13
14-- Настройка автоматического обновления
15SELECT add_continuous_aggregate_policy('hourly_stats',
16    start_offset => INTERVAL '3 hours',
17    end_offset => INTERVAL '1 hour',
18    schedule_interval => INTERVAL '30 minutes');

Политики хранения и сжатия

 1-- Настройка автоматического удаления старых данных
 2SELECT add_retention_policy('sensor_data', INTERVAL '90 days');
 3
 4-- Настройка сжатия данных старше 7 дней
 5ALTER TABLE sensor_data SET (
 6    timescaledb.compress,
 7    timescaledb.compress_segmentby = 'sensor_id',
 8    timescaledb.compress_orderby = 'time DESC'
 9);
10
11SELECT add_compression_policy('sensor_data', INTERVAL '7 days');

Интеграция с Python

 1import psycopg2
 2import pandas as pd
 3from datetime import datetime, timedelta
 4
 5# Подключение к базе данных
 6conn = psycopg2.connect(
 7    host="localhost",
 8    database="timeseries_db",
 9    user="postgres",
10    password="password"
11)
12
13# Массовая вставка данных
14def insert_sensor_data(sensor_id, readings):
15    cursor = conn.cursor()
16    
17    insert_query = """
18        INSERT INTO sensor_data (time, sensor_id, temperature, humidity)
19        VALUES %s
20    """
21    
22    data = [(reading['time'], sensor_id, reading['temp'], reading['humidity'])
23            for reading in readings]
24    
25    psycopg2.extras.execute_values(cursor, insert_query, data)
26    conn.commit()
27
28# Запрос данных с pandas
29def get_sensor_stats(sensor_id, hours_back=24):
30    query = """
31        SELECT 
32            time_bucket('1 hour', time) as hour,
33            AVG(temperature) as avg_temp,
34            MAX(temperature) as max_temp,
35            MIN(temperature) as min_temp
36        FROM sensor_data
37        WHERE sensor_id = %s AND time >= NOW() - INTERVAL '%s hours'
38        GROUP BY hour
39        ORDER BY hour
40    """
41    
42    return pd.read_sql_query(query, conn, params=[sensor_id, hours_back])
43
44# Поиск аномалий
45def detect_anomalies(sensor_id, threshold=2.0):
46    query = """
47        WITH stats AS (
48            SELECT AVG(temperature) as mean_temp, 
49                   STDDEV(temperature) as stddev_temp
50            FROM sensor_data 
51            WHERE sensor_id = %s AND time >= NOW() - INTERVAL '1 day'
52        )
53        SELECT time, temperature, 
54               ABS(temperature - stats.mean_temp) / stats.stddev_temp as z_score
55        FROM sensor_data, stats
56        WHERE sensor_id = %s 
57          AND time >= NOW() - INTERVAL '1 hour'
58          AND ABS(temperature - stats.mean_temp) / stats.stddev_temp > %s
59        ORDER BY time DESC
60    """
61    
62    return pd.read_sql_query(query, conn, params=[sensor_id, sensor_id, threshold])

Мониторинг и оптимизация

 1-- Просмотр информации о hypertables
 2SELECT * FROM timescaledb_information.hypertables;
 3
 4-- Статистика по chunks (партициям)
 5SELECT * FROM timescaledb_information.chunks
 6WHERE hypertable_name = 'sensor_data'
 7ORDER BY range_start DESC;
 8
 9-- Статистика сжатия
10SELECT 
11    hypertable_name,
12    total_chunks,
13    number_compressed_chunks,
14    before_compression_total_bytes,
15    after_compression_total_bytes,
16    compression_ratio
17FROM timescaledb_information.compression_stats;

Случаи использования TimescaleDB

  • IoT и сенсорные данные — сбор метрик с устройств
  • Мониторинг инфраструктуры — DevOps метрики
  • Финансовые данные — цены акций, торговые данные
  • Логирование приложений — анализ производительности
  • Промышленная аналитика — данные с производственных линий

Преимущества TimescaleDB

  • Полная совместимость с PostgreSQL и его экосистемой
  • Автоматическая оптимизация для временных данных
  • Эффективное сжатие и управление хранением
  • Масштабируемость до миллионов записей в секунду
  • Богатые возможности аналитики с SQL

Рекомендации по использованию

  • Выбирай подходящий интервал партицирования на основе паттернов запросов
  • Используй непрерывные агрегаты для часто выполняемых аналитических запросов
  • Настрой политики сжатия и хранения с самого начала
  • Создавай индексы на часто используемые в WHERE колонки

FAQ

В чём разница между TimescaleDB и InfluxDB?

TimescaleDB предоставляет полную SQL совместимость и интеграцию с PostgreSQL экосистемой, в то время как InfluxDB имеет собственный язык запросов и оптимизирован исключительно для временных рядов.

Можно ли использовать TimescaleDB для обычных реляционных данных?

Да, поскольку TimescaleDB — это расширение PostgreSQL, ты можешь использовать обычные таблицы наряду с hypertables в одной базе данных.