TimescaleDB сжимает временные ряды до 98%. Обычные алгоритмы из PostgreSQL — вроде TOAST — тут не годятся. TOAST сжимает только большие поля вроде длинных строк или jsonb, когда одна запись превышает 2 КБ, и делает это тупо, без оглядки на структуру данных. Для временных рядов это бесполезно: TOAST не сожмёт метку времени или число с плавающей точкой от слова совсем. TimescaleDB решает другую задачу — ищет повторяющиеся паттерны между строками.
За сжатие отвечает движок hypercore. Это гибридный row-columnar engine: новые данные падают в обычные строчные чанки — быстро пишутся и обновляются, — а старые чанки автоматически конвертируются в колоночный формат и сжимаются. Каждый сжатый чанк делит строки на батчи примерно по 1000 штук. Внутри батча данные хранятся по колонкам, а не по строкам. Запрос может вытащить только нужные колонки, не читая весь чанк целиком.
TimescaleDB подбирает алгоритм под тип колонки. Для целых чисел, таймстемпов и булевых — комбинация delta encoding, delta-of-delta, simple-8b и run-length encoding (RLE). Если интервал между замерами постоянный, delta-of-delta даёт ноль, который упаковывается в пару бит. Для чисел с плавающей точкой вроде показаний температуры — XOR-сжатие на основе Gorilla: близкие флоаты при XOR дают много ведущих и завершающих нулей, остаётся сохранить только значащую середину. Для JSONB — сначала словарь, потом TOAST как запасной вариант. Для строк — словарное сжатие, двухступенчатое, с RLE на индексах.
Ключевые настройки — segmentby и orderby. segmentby задаёт колонку, по которой строки группируются в общий батч (например, machine_id). Значение хранится один раз на батч, а planner использует метаданные, чтобы целиком пропускать не подходящие батчи. orderby — сортировка внутри батча (обычно time DESC). Чем ближе соседние значения, тем меньше разность — тем лучше сжатие. Если segmentby выбран плохо и у каждого ID в чанке всего несколько строк, батчи будут недозаполнены и сжатие провалится. Правило: минимум 100 строк на сегмент в чанке, оптимально 100–10000 уникальных segmentby-значений.
Сжатие не экономит место в ущерб скорости. Для типовых time-series запросов — range scans с аггрегацией, фильтр по segmentby, sequential scans на больших диапазонах — оно ускоряет запросы. Колоночное хранение снижает I/O в 10–20 раз. TimescaleDB сама строит индекс (segmentby_col, _ts_meta_min_1, _ts_meta_max_1), который отсекает батчи по мета-информации, не читая данные. Работа идёт батчами по 1000 строк — векторное выполнение, а не построчное. В примере из статьи с данными MQTT: сжатый чанк (7.2 MB против исходных 308 MB, сжатие в 42×) отработал запрос за 0.36 мс против 10.2 мс на строчном — ускорение в 28 раз. RoszigIT проектирует стеки Grafana + TimescaleDB + AWS для промышленности.