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

Важную роль в обеспечении высокой производительности 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 and restart для сервиса 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 чтобы сообщить о ней