Расширенные типы данных

Этот документ описывает расширенные типы данных, поддерживаемые YMatrix, которые можно использовать для построения моделей широких/узких таблиц.

YMatrix — это реляционная база данных со схемой. Все таблицы должны иметь предварительно определённую схему, заданную с помощью DDL-заявлений. Каждый столбец в схеме представляет атрибутное значение, например, имя, рост или вес. Однако в некоторых бизнес-сценариях часто возникают следующие проблемы:

  1. Набор метрик непредсказуем, что означает необходимость частого изменения схемы таблицы.
  2. Количество метрик превышает максимальный лимит столбцов YMatrix — 1600.
  3. Наборы метрик значительно различаются между строками, что приводит к большому количеству значений NULL при извлечении данных.

Для решения этих проблем несколько атрибутов могут быть сериализованы и сохранены в полях переменной длины.

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

Существует множество способов реализации расширенных типов данных. Например, можно определить пользовательские форматы сериализации и методы кодирования и хранить их в столбцах типа строка. YMatrix предоставляет следующие расширенные типы данных:

Сравнение:

Тип данных Формат хранения Поддерживаемые форматы хранения Поддерживаемые форматы данных
JSON Текст Все форматы INT/NUMERIC/BOOLEAN/NULL и др.
Поддерживает хранение различных типов данных в массивах внутри одного столбца JSON
JSONB Бинарный Все форматы INT/NUMERIC/BOOLEAN/NULL и др.
Поддерживает хранение различных типов данных в массивах внутри одного столбца JSON
MXKV Бинарный Все форматы MXKV_INT4/MXKV_FLOAT4/MXKV_FLOAT8/MXKV_TEXT
Поддерживает только плоскую структуру ключ-значение; вложенность и массивы не допускаются. Для хранения метрик разных типов требуются несколько столбцов
MXKV2 Бинарный MARS2/3 MXKV_INT8/MXKV_FLOAT8/MXKV_TEXT/MXKV_BOOL
Поддерживает только плоскую структуру ключ-значение; вложенность и массивы не допускаются. Для хранения метрик разных типов требуются несколько столбцов


1 JSON/JSONB

Типы данных JSON и JSONB унаследованы от PostgreSQL. В отличие от прямого хранения строк JSON в текстовых столбцах, типы JSON/JSONB предоставляют встроенные функции для распространённых операций с JSON, таких как извлечение ключей и значений, объединение и удаление.

JSON и JSONB используются аналогично и могут взаимно преобразовываться. Их различия:

  1. JSON хранится как текст; JSONB хранится в бинарном формате.
  2. JSON обеспечивает более высокую производительность записи, так как при вставке не требуется преобразование в бинарный формат.
  3. JSONB обеспечивает более быстрый парсинг благодаря бинарному хранению.
  4. JSONB поддерживает индексирование.

Ниже приведены распространённые операции с типами JSON/JSONB:

1.1 Извлечение ключа и значения с помощью ->

=# SELECT '{"a":1, "b":2, "c":3}'::json->'a';
 ?column?
----------
 1
(1 row)

Для вложенных структур JSON/JSONB используйте -> несколько раз:

=# SELECT '{"a":1, "b":2, "c":{"d":2}}'::json->'c'->'d';
 ?column?
----------
 2
(1 row)

1.2 Удаление ключа и значения

Используйте оператор - для удаления ключа. При выполнении операций записи над объектами JSON данные должны быть приведены к типу JSONB:

=# SELECT '{"a":1, "b":2, "c":3}'::jsonb - 'a';
     ?column?
------------------
 {"b": 2, "c": 3}
(1 row)

1.3 Объединение ключей и значений

Используйте оператор || для объединения двух объектов JSONB:

=# SELECT '{"a":1, "b":2}'::jsonb || '{"c":3}'::jsonb;
         ?column?
--------------------------
 {"a": 1, "b": 2, "c": 3}
(1 row)

1.4 Обновление ключа и значения

При совпадении ключей использование || обновляет значение:

=# SELECT '{"a":1, "b":2}'::jsonb || '{"b":3}'::jsonb;
     ?column?
------------------
 {"a": 1, "b": 3}
(1 row)

Для дополнительных операций с JSON обратитесь к документации PostgreSQL здесь.


2 MXKV / MXKV2

MXKV и MXKV2 — это разработанные YMatrix высокопроизводительные и масштабируемые типы хранения, используемые аналогично JSON/JSONB. Их преимущество заключается в бинарном хранении в сочетании с алгоритмами сжатия цепочки кодирования YMatrix, что обеспечивает меньший объём хранения и более высокую эффективность запросов.

Помимо различий, указанных в таблице сравнения, MXKV и MXKV2 отличаются следующим:

  • Импорт ключей: MXKV требует ручного импорта ключей; MXKV2 — нет.
  • Производительность: MXKV2 обеспечивает наивысший коэффициент сжатия и наилучшую производительность запросов, за ним следуют MXKV, затем JSONB и, наконец, JSON.
  • Векторизованное выполнение: MXKV2 достигает своих преимуществ производительности только при использовании с векторизованным движком выполнения; MXKV не получает выгод от векторизации.
  • Спецификация сжатия: При создании таблиц MXKV2 требует указания метода сжатия; MXKV — нет.

Обучающие видео по этому разделу доступны в Моделировании данных YMatrix и спatio-temporal моделях

Примечание!
Эта функция доступна только в корпоративной версии.

2.1 Использование

2.1.1 Создание расширения и проверка

Пользовательские типы данных MXKV и MXKV2 включены в расширение MatrixTS. Сначала создайте расширение:

=# CREATE EXTENSION matrixts;

Проверьте, что MXKV/MXKV2 включены:

// MXKV
=# SELECT '{}'::mxkv_text;
 mxkv_text
-----------
 {}
(1 row)

// MXKV2
=# SELECT '{}'::mxkv2_text;
 mxkv2_text
-----------
 {}
(1 row)

Как показано, MXKV включён.

2.1.2 Создание таблицы с столбцом MXKV

Создайте новую таблицу и определите столбец целочисленного типа для хранения KV-данных с целочисленными значениями:

// MXKV
=# CREATE TABLE data_1(
    time timestamp with time zone,
    tag_id int,
    kv mxkv_int4
   )
   USING MARS3
   DISTRIBUTED BY (tag_id)
   ORDER BY (time,tag_id);

// MXKV2
=# CREATE TABLE data_2(
    time timestamp with time zone,
    tag_id int,
    kv mxkv2_int8 encoding(compresstype=mxcustom,encodechain='auto')
   )
   USING MARS3
   DISTRIBUTED BY (tag_id)
   ORDER BY (time,tag_id);

2.1.3 Определение ключей (пропустить для MXKV2)

Перед использованием MXKV необходимо определить ключи для оптимизации сжатия и производительности запросов. Этот шаг предварительно задаёт набор ожидаемых ключей в данных.

MXKV предоставляет UDF mxkv_import_keys для определения ключей.

Доступны два метода:

  • Ручное определение

Предоставьте пример KV в формате JSON. MXKV автоматически извлечёт и определит ключи.

Следующий SQL-запрос извлекает и определяет ключи 'a' и 'b' из JSON:

=# SELECT mxkv_import_keys('{"a": 1, "b": 2}');
 mxkv_import_keys
------------------
 a
 b
(2 rows)
  • Определение из существующих данных таблицы

Предположим, существует таблица t_json с JSON-столбцом c2:

=# SELECT c2 FROM t_json ;
    c2
----------
 {"k1":1}
 {"k2":2}
(2 rows)

Результат показывает два ключа: k1 и k2.

Используйте mxkv_import_keys для определения ключей из данных таблицы:

=# SELECT mxkv_import_keys('t_json'::regclass, 'c2');
 mxkv_import_keys
------------------
 k1
 k2
(2 rows)

Как показано, передайте имя таблицы и имя столбца в качестве параметров.
Этот метод удобнее и быстрее, но требует, чтобы выборочные данные уже существовали в другой таблице.

Примечание!
Ключи в MXKV должны быть определены до вставки данных. В противном случае возникнет следующая ошибка:
DETAIL: The key is not imported yet HINT: Import the keys with the mxkv_import_keys() function

2.1.4 Вставка данных

После определения ключей вставьте KV-данные:

// MXKV
=# INSERT INTO data_1 VALUES(now(), 1, '{"a":1, "b":2}');
INSERT 0 1

// MXKV2
=# INSERT INTO data_2 VALUES(now(), 1, '{"a":1, "b":2}');
INSERT 0 1

Как показано, вставленные KV-данные содержат ранее определённые ключи 'a' и 'b'.

2.1.5 Чтение содержимого ключа и значения

Чтение ключей и значений в MXKV использует тот же оператор ->, что и в JSON:

// MXKV
=# SELECT time, tag_id, kv->'a' as a, kv->'b' as b FROM data_1;
             time              | tag_id | a | b
-------------------------------+--------+---+---
 2023-10-19 10:20:05.334169+00 |      1 | 1 | 2
(1 row)

// MXKV2
=# SELECT time, tag_id, kv->'a' as a, kv->'b' as b FROM data_2;
             time              | tag_id | a | b
-------------------------------+--------+---+---
 2023-10-19 10:20:05.334169+00 |      1 | 1 | 2
(1 row)

Извлечённые ключи и значения можно использовать как обычные столбцы — для сравнений или соединений с другими таблицами. Например, создайте таблицу data_1/data_2 с такой же структурой, как data_1, и вставьте идентичные данные. Следующий SQL-запрос выполняет соединение:

// MXKV
=# SELECT * FROM data_1, data_3 WHERE data_1.kv->'a' = data_3.kv->'a';
             time              | tag_id |        kv        |             time              | tag_id |        kv
-------------------------------+--------+------------------+-------------------------------+--------+------------------
 2023-10-19 10:20:05.334169+00 |      1 | {"a": 1, "b": 2} | 2023-10-19 10:20:05.334169+00 |      1 | {"a": 1, "b": 2}
(1 row)

// MXKV2
=# SELECT * FROM data_2, data_3 WHERE data_2.kv->'a' = data_3.kv->'a';
             time              | tag_id |        kv        |             time              | tag_id |        kv
-------------------------------+--------+------------------+-------------------------------+--------+------------------
 2023-10-19 10:20:05.334169+00 |      1 | {"a": 1, "b": 2} | 2023-10-19 10:20:05.334169+00 |      1 | {"a": 1, "b": 2}
(1 row)

Примечание!
В MXKV/MXKV2 -> и ->> эквивалентны.

2.2 Поддерживаемые форматы данных для MXKV/MXKV2

Тип данных Поддерживаемые форматы данных
MXKV MXKV_INT4: хранит 32-битные целые числа (INT4/INT)
MXKV_FLOAT4: хранит 32-битные числа с плавающей точкой (FLOAT4/REAL)
MXKV_FLOAT8: хранит 64-битные числа с плавающей точкой (FLOAT8/FLOAT/DOUBLE PRECISION)
MXKV_TEXT: хранит строки TEXT
MXKV2 MXKV2_INT8: хранит 64-битные целые числа (INT8/INT)
MXKV2_FLOAT8: хранит 64-битные числа с плавающей точкой (FLOAT8/FLOAT/DOUBLE PRECISION)
MXKV2_TEXT: хранит строки TEXT
MXKV2_BOOL: хранит логические значения BOOLEAN

MXKV_FLOAT4 и MXKV_FLOAT8 поддерживают указание масштаба десятичных знаков. Например:

=# CREATE TABLE data_4(
    time timestamp with time zone,
    tag_id int,
    kv mxkv_float4(2)
   )
   USING MARS3
   DISTRIBUTED BY (tag_id)
   ORDER BY (time,tag_id);

При таком определении цифры после двух десятичных знаков округляются.

Указание масштаба преобразует внутреннее хранение в целочисленный формат, улучшая сжатие и эффективность. Однако диапазон значений соответственно уменьшается.

  • mxkv_float4(scale), scale >= 0
    • mxkv_float4(0): [-2147483500, 2147483500]
    • mxkv_float4(2): [-21474835.00, 21474835.00]
    • mxkv_float4(4): [-214748.3500, 214748.3500]
    • ......
  • mxkv_float8(scale), scale >= 0
    • mxkv_float8(0): [-9223372036854775000, 9223372036854775000]
    • mxkv_float8(2): [-92233720368547750.00, 92233720368547750.00]
    • mxkv_float8(4): [-922337203685477.5000, 922337203685477.5000]
    • ......

Примечание!
MXKV и MXKV2 поддерживают только плоские структуры ключ-значение. Вложенность и массивы не допускаются.
Для получения дополнительных технических деталей см. блог MXKV.