Сжатие данных

Важную роль в обеспечении высокой производительности ADQM играет сжатие — или компрессия — данных (data compression). Например, с помощью сжатия можно уменьшить объем данных, считываемых при выполнении запроса, и тем самым ускорить этот запрос — см. пример в статье Повышение производительности запросов.

ADQM поддерживает сжатие данных для следующих табличных движков:

  • MergeTree — возможно установить алгоритм сжатия по умолчанию для таблиц, а также указать свой метод сжатия (или их комбинацию) для каждого отдельного столбца при создании/модификации таблицы (см. раздел Применение кодеков сжатия ниже).

  • Log — метод сжатия LZ4 используется по умолчанию, поддерживается возможность устанавливать сжатие по столбцам.

  • Set, Join — поддерживается только сжатие по умолчанию.

Кодеки сжатия данных

Алгоритм сжатия, применяемый к данным ADQM, определяется кодеком. В ADQM доступны следующие кодеки сжатия данных:

  • Кодеки общего назначения, позволяющие находить оптимальное соотношение между потреблением дискового пространства и ресурсов CPU.

  • Специализированные кодеки для определенных типов данных. Некоторые из этих кодеков не сжимают данные самостоятельно, а выполняют их предварительную обработку (учитывая особенности типа данных) для кодеков общего назначения, которые в свою очередь сжимают подготовленные данные эффективнее, чем неподготовленные.

Кодеки общего назначения

Кодек Алгоритм сжатия Уровень сжатия (level)

NONE

Сжатие данных не применяется

 — 

LZ4

Алгоритм сжатия без потерь LZ4. Обеспечивает высокую скорость и хорошую степень сжатия. Используется по умолчанию

 — 

LZ4HC[(level)]

Алгоритм LZ4 HC (high compression) с настраиваемым уровнем сжатия. По сравнению с LZ4 сжимает данные лучше, но медленнее, при этом обеспечивает такую же быструю декомпрессию

Возможные уровни сжатия — [1, 12], рекомендуемый диапазон — [4, 9]. Уровень сжатия по умолчанию (если не указан или указано значение, меньшее или равное 0) — 9

ZSTD[(level)]

Алгоритм сжатия ZSTD. Обеспечивает как скорость, так и высокую степень сжатия, которую можно настроить. Без применения специализированного кодека подготовки данных часто превосходит другие методы сжатия или, по крайней мере, конкурентоспособен

Возможные уровни сжатия — [1, 22]. Уровень сжатия по умолчанию — 1.

Уровни сжатия выше 3 редко приводят к значительному улучшению результата, однако высокие уровни сжатия (которые предполагают лучшее сжатие, но большее использование CPU) могут быть полезны для асимметричных сценариев — например, "одно сжатие, многократная декомпрессия". В любом случае рекомендуется проводить тестирование

ZSTD_QAT[(level)]

Алгоритм сжатия ZSTD с настраиваемым уровнем сжатия, который реализуют Intel QATlib и Intel QAT ZSTD Plugin. Особенности использования:

  • Кодек ZSTD_QAT отключен по умолчанию и может использоваться только после включения параметра: SET enable_zstd_qat_codec = 1.

  • Для сжатия ZSTD_QAT пытается использовать устройство разгрузки Intel QuickAssist Technology (QAT). Если такое устройство не найдено, сжатие выполняется программно.

  • Декомпрессия всегда выполняется программно.

Возможные уровни сжатия — [1, 12], рекомендуемый диапазон — [6, 12]. Уровень сжатия по умолчанию — 1

DEFLATE_QPL

Алгоритм сжатия Deflate, реализованный Intel Query Processing Library (Intel QPL). Особенности использования:

  • Кодек DEFLATE_QPL отключен по умолчанию и может использоваться только после включения параметра: SET enable_deflate_qpl_codec = 1.

  • DEFLATE_QPL работает лучше всего, если в системе установлено устройство разгрузки Intel In-Memory Analytics Accelerator (IAA) — см. Accelerator Configuration и Benchmark with DEFLATE_QPL.

Техническая поддержка по этому кодеку для ADQM предоставляется в ограниченной форме

 — 

Специализированные кодеки

Кодек Описание Параметры

Delta(delta_bytes)

Заменяет исходные значения разницей (дельтой) двух соседних значений (за исключением первого значения, которое остается неизменным). Хорошо работает с монотонно возрастающими значениями.

Delta — кодек подготовки данных для дальнейшего сжатия, то есть его нельзя использовать отдельно (без дополнительного кодека сжатия)

delta_bytes — ограничение (в байтах) для хранения разниц, то есть это максимальный размер исходных значений. Возможные значения delta_bytes — 1, 2, 4, 8. Значение по умолчанию равно sizeof(type), если результат 1, 2, 4 или 8. Во всех остальных случаях — 1

DoubleDelta(bytes_size)

Вычисляет разницу между соседними дельтами и сохраняет ее в компактном бинарном виде.

Оптимальная степень сжатия достигается для монотонных последовательностей с постоянным шагом (например, временных рядов). Может использоваться с любым типом данных фиксированного размера. Реализует алгоритм, используемый в Gorilla TSDB, адаптируя его для работы c 64-битными типами данных. Использует 1 дополнительный бит для 32-битных дельт: 5-битные префиксы вместо 4-битных. Подробнее читайте в разделе Compressing Time Stamps статьи Gorilla: A Fast, Scalable, In-Memory Time Series Database.

DoubleDelta — кодек подготовки данных для дальнейшего сжатия, то есть его нельзя использовать отдельно (без дополнительного кодека сжатия)

Возможные значения bytes_size — 1, 2, 4, 8. Значение по умолчанию равно sizeof(type), если результат 1, 2, 4 или 8. Во всех остальных случаях  — 1

GCD

Вычисляет наибольший общий знаменатель (Greatest Common Denominator, GCD) значений в столбце, затем делит каждое значение на GCD. Может использоваться с целочисленными, десятичными столбцами и столбцами типа DateTime. Также хорошо подходит для столбцов, значения которых изменяются (увеличиваются или уменьшаются) кратно GCD — например, 24, 28, 16, 24, 8, 24 (GCD = 4).

GCD — кодек подготовки данных для дальнейшего сжатия, то есть его нельзя использовать отдельно (без дополнительного кодека сжатия)

 — 

Gorilla(bytes_size)

Вычисляет XOR между текущим и предыдущим значением с плавающей запятой и записывает результат в компактной бинарной форме. Чем меньше разница между последовательными значениями (то есть чем медленнее изменяются значения ряда), тем лучше степень сжатия. Реализует алгоритм, используемый в Gorilla TSDB, адаптируя его для работы с 64-битными значениями. Дополнительную информацию можно найти в разделе Compressing values статьи Gorilla: A Fast, Scalable, In-Memory Time Series Database

Возможные значения bytes_size — 1, 2, 4, 8. Значение по умолчанию равно sizeof(type), если результат 1, 2, 4 или 8. Во всех остальных случаях — 1

FPC(level, float_size)

Повторно прогнозирует следующее значение с плавающей запятой в последовательности, используя лучший из двух предикторов, затем вычисляет XOR фактического значения с предсказанным значением и сжимает результат с ведущим нулем. Подобно Gorilla, FPC эффективно сохраняет ряды медленно изменяющихся значений с плавающей запятой. Для 64-битных значений FPC работает быстрее, чем Gorilla; для 32-битных значений — оценка может измениться. См. подробное описание алгоритма в статье High Throughput Compression of Double-Precision Floating-Point Data

Возможные значения параметра level — [1, 28], значение по умолчанию — 12.

Возможные значения float_size — 4, 8, значение по умолчанию — sizeof(type), если тип — Float. Во всех остальных случаях — 4

T64

Обрезает неиспользуемые старшие биты целочисленных значений (включая Enum, Date и DateTime). На каждом шаге алгоритма кодек помещает блок из 64 значений в битовую матрицу размером 64x64, транспонирует ее, обрезает неиспользуемые биты значений и возвращает то, что осталось, в виде последовательности. Неиспользуемые биты — это биты, которые не изменяются от минимального к максимальному на всем диапазоне значений куска данных, для которого используется сжатие

 — 

Кодеки DoubleDelta и Gorilla используются в Gorilla TSDB в качестве компонентов алгоритма сжатия. Подход Gorilla эффективен в сценариях, когда данные представляют собой последовательность медленно меняющихся значений с их временными метками. Временные метки эффективно сжимаются кодеком DoubleDelta, а значения — кодеком Gorilla.

Применение кодеков сжатия

На уровне сервера

По умолчанию к столбцам таблиц семейства MergeTree ADQM применяет метод сжатия, определенный в конфигурации сервера. Изменить настройки сжатия по умолчанию можно в секции Data compression на странице конфигурации сервиса ADQMDB. Эта секция становится видимой при включенной опции Show advanced. Для доступа к параметрам конфигурации и их применения необходимо активировать переключатель Data compression.

Настройка сжатия данных таблиц MergeTree на уровне сервера
Настройка сжатия данных таблиц MergeTree на уровне сервера

После определения параметров сжатия данных нажмите Save и выполните действие Reconfig для сервиса ADQMDB.

ПРИМЕЧАНИЕ

Изменение настроек сжатия по умолчанию не влияет на уже существующие таблицы.

На уровне столбцов

Метод сжатия можно указать для каждого столбца отдельно в запросе CREATE TABLE с помощью выражения CODEC:

CREATE TABLE <table_name>
(   <column_name1> <data_type1> CODEC(<compression_codec1>) [...],
    <column_name2> <data_type2> CODEC(<compression_codec2>) [...],
    ...)
ENGINE = MergeTree()
...;

Если для столбца указан кодек Default (CODEC(Default)) или кодек не указан, используется алгоритм сжатия по умолчанию, установленный на уровне сервера.

Кодеки можно последовательно комбинировать — например, при использовании специализированного кодека, чтобы подготовить данные для более эффективного сжатия кодеком общего назначения (CODEC(Delta, ZSTD)).

Изменить кодек сжатия столбца уже существующей таблицы можно с помощью следующего запроса:

ALTER TABLE <table_name> MODIFY COLUMN <column_name> CODEC(<new_compression_codec>);

Общие рекомендации

Для наиболее эффективного сжатия данных рекомендуется:

  • Выбирать наиболее подходящий под конкретную задачу алгоритм сжатия, учитывая тип и характер данных (если известны).

  • При выборе уровня сжатия данных следует помнить: чем выше этот уровень — тем больше, но дольше по времени сжатие данных. Фактически сжатие данных позволяет улучшить показатели I/O и уменьшить размер данных за счет ресурсов CPU. Постарайтесь найти оптимальные настройки — чтобы избежать длительного сжатия и медленного сканирования данных.

  • Конечная производительность сжатых таблиц зависит от множества факторов, включая аппаратное обеспечение, параметры запросов и так далее. Всегда проводите тестирование — чтобы определить, насколько эффективно сжатие данных в конкретном окружении.

РЕКОМЕНДАЦИЯ
Необходимо всегда соблюдать баланс между доступными ресурсами CPU и требуемой скоростью сжатия.

Пример

Создайте таблицу MergeTree со столбцами типа Int64 и Float64, применяя к ним кодеки сжатия данных LZ4 и ZSTD в комбинации с различными специализированными кодеками подготовки данных:

CREATE TABLE compression_test (
    n Int32,
    i64 Int64 DEFAULT n CODEC(NONE),
    i64_lz4 Int64 DEFAULT n CODEC(LZ4),
    i64_delta_lz4 Int64 DEFAULT n CODEC(Delta, LZ4),
    i64_doubledelta_lz4 Int64 DEFAULT n CODEC(DoubleDelta, LZ4),
    i64_t64_lz4 Int64 DEFAULT n CODEC(T64, LZ4),
    i64_zstd Int64 DEFAULT n CODEC(ZSTD),
    i64_delta_zstd Int64 DEFAULT n CODEC(Delta, ZSTD),
    i64_doubledelta_zstd Int64 DEFAULT n CODEC(DoubleDelta, ZSTD),
    i64_t64_zstd Int64 DEFAULT n CODEC(T64, ZSTD),
    f64 Float64 DEFAULT n CODEC(NONE),
    f64_lz4 Float64 DEFAULT n CODEC(LZ4),
    f64_delta_lz4 Float64 DEFAULT n CODEC(Delta, LZ4),
    f64_doubledelta_lz4 Float64 DEFAULT n CODEC(DoubleDelta, LZ4),
    f64_gorilla_lz4 Float64 DEFAULT n CODEC(Gorilla, LZ4),
    f64_fpc_lz4 Float64 DEFAULT n CODEC(FPC, LZ4),
    f64_zstd Float64 DEFAULT n CODEC(ZSTD),
    f64_delta_zstd Float64 DEFAULT n CODEC(Delta, ZSTD),
    f64_doubledelta_zstd Float64 DEFAULT n CODEC(DoubleDelta, ZSTD),
    f64_gorilla_zstd Float64 DEFAULT n CODEC(Gorilla, ZSTD),
    f64_fpc_zstd Float64 DEFAULT n CODEC(FPC, ZSTD))
Engine = MergeTree()
ORDER BY tuple();

Сгенерируйте тестовые данные для таблицы (1 миллион строк) так, чтобы каждый столбец содержал монотонную последовательность чисел со случайным инкрементом:

INSERT INTO compression_test (n) SELECT number*1000+(rand()%100) FROM numbers(1000000);

Используйте системную таблицу system.columns, чтобы посмотреть размер данных в сжатом и несжатом виде для каждого столбца и кодеки сжатия столбцов:

SELECT
    name,
    type,
    formatReadableSize(data_uncompressed_bytes) AS uncompressed,
    formatReadableSize(data_compressed_bytes) AS compressed,
    round(data_uncompressed_bytes / data_compressed_bytes, 2) AS ratio,
compression_codec codec
FROM system.columns
WHERE table = 'compression_test' AND name != 'n';

В результате этого тестирования видно, что применение специализированных кодеков может существенно повлиять на уровень сжатия данных кодеками общего назначения в зависимости от типа данных столбца. Например, для типа Int64 оба алгоритма (LZ4 и ZSTD) обеспечивают лучшее сжатие вместе с кодеком DoubleDelta, а для типа Float64 — ZSTD вместе с Delta или FPC.

    ┌─name─────────────────┬─type────┬─uncompressed─┬─compressed─┬─ratio─┬─codec───────────────────────┐
 1. │ i64                  │ Int64   │ 7.63 MiB     │ 7.63 MiB   │     1 │ CODEC(NONE)                 │
 2. │ i64_lz4              │ Int64   │ 7.63 MiB     │ 4.78 MiB   │   1.6 │ CODEC(LZ4)                  │
 3. │ i64_delta_lz4        │ Int64   │ 7.63 MiB     │ 2.89 MiB   │  2.64 │ CODEC(Delta(8), LZ4)        │
 4. │ i64_doubledelta_lz4  │ Int64   │ 7.63 MiB     │ 1.23 MiB   │  6.21 │ CODEC(DoubleDelta, LZ4)     │
 5. │ i64_t64_lz4          │ Int64   │ 7.63 MiB     │ 1.62 MiB   │  4.72 │ CODEC(T64, LZ4)             │
 6. │ i64_zstd             │ Int64   │ 7.63 MiB     │ 1.97 MiB   │  3.87 │ CODEC(ZSTD(1))              │
 7. │ i64_delta_zstd       │ Int64   │ 7.63 MiB     │ 1.36 MiB   │  5.62 │ CODEC(Delta(8), ZSTD(1))    │
 8. │ i64_doubledelta_zstd │ Int64   │ 7.63 MiB     │ 1.22 MiB   │  6.23 │ CODEC(DoubleDelta, ZSTD(1)) │
 9. │ i64_t64_zstd         │ Int64   │ 7.63 MiB     │ 1.42 MiB   │  5.36 │ CODEC(T64, ZSTD(1))         │
10. │ f64                  │ Float64 │ 7.63 MiB     │ 7.63 MiB   │     1 │ CODEC(NONE)                 │
11. │ f64_lz4              │ Float64 │ 7.63 MiB     │ 5.01 MiB   │  1.52 │ CODEC(LZ4)                  │
12. │ f64_delta_lz4        │ Float64 │ 7.63 MiB     │ 2.90 MiB   │  2.63 │ CODEC(Delta(8), LZ4)        │
13. │ f64_doubledelta_lz4  │ Float64 │ 7.63 MiB     │ 3.47 MiB   │   2.2 │ CODEC(DoubleDelta, LZ4)     │
14. │ f64_gorilla_lz4      │ Float64 │ 7.63 MiB     │ 2.66 MiB   │  2.87 │ CODEC(Gorilla, LZ4)         │
15. │ f64_fpc_lz4          │ Float64 │ 7.63 MiB     │ 3.11 MiB   │  2.45 │ CODEC(FPC(12), LZ4)         │
16. │ f64_zstd             │ Float64 │ 7.63 MiB     │ 2.22 MiB   │  3.44 │ CODEC(ZSTD(1))              │
17. │ f64_delta_zstd       │ Float64 │ 7.63 MiB     │ 1.49 MiB   │  5.11 │ CODEC(Delta(8), ZSTD(1))    │
18. │ f64_doubledelta_zstd │ Float64 │ 7.63 MiB     │ 2.05 MiB   │  3.72 │ CODEC(DoubleDelta, ZSTD(1)) │
19. │ f64_gorilla_zstd     │ Float64 │ 7.63 MiB     │ 2.32 MiB   │  3.29 │ CODEC(Gorilla, ZSTD(1))     │
20. │ f64_fpc_zstd         │ Float64 │ 7.63 MiB     │ 1.87 MiB   │  4.08 │ CODEC(FPC(12), ZSTD(1))     │
    └──────────────────────┴─────────┴──────────────┴────────────┴───────┴─────────────────────────────┘

При этом, например, на случайных данных Delta и DoubleDelta не очень хорошо работают как видно в примере ниже. Такие данные лучше сжимаются с использованием T64 для целочисленных значение и Gorilla для чисел с плавающей запятой — то есть эти кодеки могут быть рекомендованы к использованию, когда характер данных неизвестен.

CREATE TABLE compression_test_rand AS compression_test;
INSERT INTO compression_test_rand (n) SELECT rand()%(1000000) FROM numbers(1000000);
SELECT
    name,
    type,
    formatReadableSize(data_uncompressed_bytes) AS uncompressed,
    formatReadableSize(data_compressed_bytes) AS compressed,
    round(data_uncompressed_bytes / data_compressed_bytes, 2) AS ratio,
compression_codec codec
FROM system.columns
WHERE table = 'compression_test_rand' AND name != 'n';
    ┌─name─────────────────┬─type────┬─uncompressed─┬─compressed─┬─ratio─┬─codec───────────────────────┐
 1. │ i64                  │ Int64   │ 7.63 MiB     │ 7.63 MiB   │     1 │ CODEC(NONE)                 │
 2. │ i64_lz4              │ Int64   │ 7.63 MiB     │ 4.40 MiB   │  1.73 │ CODEC(LZ4)                  │
 3. │ i64_delta_lz4        │ Int64   │ 7.63 MiB     │ 4.63 MiB   │  1.65 │ CODEC(Delta(8), LZ4)        │
 4. │ i64_doubledelta_lz4  │ Int64   │ 7.63 MiB     │ 4.43 MiB   │  1.72 │ CODEC(DoubleDelta, LZ4)     │
 5. │ i64_t64_lz4          │ Int64   │ 7.63 MiB     │ 2.40 MiB   │  3.18 │ CODEC(T64, LZ4)             │
 6. │ i64_zstd             │ Int64   │ 7.63 MiB     │ 3.32 MiB   │   2.3 │ CODEC(ZSTD(1))              │
 7. │ i64_delta_zstd       │ Int64   │ 7.63 MiB     │ 3.42 MiB   │  2.23 │ CODEC(Delta(8), ZSTD(1))    │
 8. │ i64_doubledelta_zstd │ Int64   │ 7.63 MiB     │ 3.84 MiB   │  1.99 │ CODEC(DoubleDelta, ZSTD(1)) │
 9. │ i64_t64_zstd         │ Int64   │ 7.63 MiB     │ 2.39 MiB   │  3.19 │ CODEC(T64, ZSTD(1))         │
10. │ f64                  │ Float64 │ 7.63 MiB     │ 7.63 MiB   │     1 │ CODEC(NONE)                 │
11. │ f64_lz4              │ Float64 │ 7.63 MiB     │ 4.67 MiB   │  1.63 │ CODEC(LZ4)                  │
12. │ f64_delta_lz4        │ Float64 │ 7.63 MiB     │ 4.85 MiB   │  1.57 │ CODEC(Delta(8), LZ4)        │
13. │ f64_doubledelta_lz4  │ Float64 │ 7.63 MiB     │ 5.94 MiB   │  1.28 │ CODEC(DoubleDelta, LZ4)     │
14. │ f64_gorilla_lz4      │ Float64 │ 7.63 MiB     │ 3.12 MiB   │  2.44 │ CODEC(Gorilla, LZ4)         │
15. │ f64_fpc_lz4          │ Float64 │ 7.63 MiB     │ 5.03 MiB   │  1.52 │ CODEC(FPC(12), LZ4)         │
16. │ f64_zstd             │ Float64 │ 7.63 MiB     │ 3.26 MiB   │  2.34 │ CODEC(ZSTD(1))              │
17. │ f64_delta_zstd       │ Float64 │ 7.63 MiB     │ 3.44 MiB   │  2.22 │ CODEC(Delta(8), ZSTD(1))    │
18. │ f64_doubledelta_zstd │ Float64 │ 7.63 MiB     │ 4.07 MiB   │  1.87 │ CODEC(DoubleDelta, ZSTD(1)) │
19. │ f64_gorilla_zstd     │ Float64 │ 7.63 MiB     │ 3.05 MiB   │   2.5 │ CODEC(Gorilla, ZSTD(1))     │
20. │ f64_fpc_zstd         │ Float64 │ 7.63 MiB     │ 4.20 MiB   │  1.82 │ CODEC(FPC(12), ZSTD(1))     │
    └──────────────────────┴─────────┴──────────────┴────────────┴───────┴─────────────────────────────┘
Нашли ошибку? Выделите текст и нажмите Ctrl+Enter чтобы сообщить о ней