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

Этот документ описывает расширенные типы данных, поддерживаемые YMatrix.

В реляционной модели обычные типы данных представляют отдельные атрибуты в столбцах, такие как имя, рост и вес. Однако в сценариях временных рядов часто возникают следующие проблемы:

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

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

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

  1. JSON / jsonb
  2. MXKV

1 JSON / jsonb

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

JSON и jsonb функционально схожи и могут быть взаимно преобразованы. Их различия заключаются в следующем:

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

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

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

Используйте оператор -> для извлечения значений по ключу:

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

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

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

1.2 Удаление ключей

Используйте оператор - для удаления ключа. Обратите внимание: операции записи требуют, чтобы значение имело тип 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

Видеоурок по этой теме доступен по ссылке: YMatrix Data Modeling and Spatiotemporal Distribution Model

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

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

Традиционные решения включают:

  1. Сериализацию нескольких столбцов в поле переменной длины.
  2. Использование типов данных JSON или jsonb.

Хотя эти подходы обеспечивают гибкость, они страдают от низкой производительности.

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

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

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

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

Тип данных MXKV входит в расширение MatrixTS. Сначала создайте расширение:

CREATE EXTENSION matrixts;

Проверьте, что MXKV включён:

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

Как показано выше, MXKV теперь активен.

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

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

CREATE TABLE data(
    time timestamp with time zone,
    tag_id int,
    kv mxkv_int4
)
DISTRIBUTED BY (tag_id);

2.1.3 Определение ключей

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

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

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

  1. Ручное определение

Укажите пример JSON-объекта вручную. MXKV автоматически извлечёт и зарегистрирует ключи.

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

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

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

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

Из вывода видно, что c2 содержит ключи k1 и k2.

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

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

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

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

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

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

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

Примечание!
Ключи должны быть определены до вставки. В противном случае возникнет ошибка:
Key not found in MXKV key registry

2.1.5 Чтение значений ключей

Чтение значений ключей из MXKV аналогично JSON и выполняется с помощью оператора ->:

mxadmin=# SELECT time, tag_id, kv->'a' as a, kv->'b' as b FROM data;
             time              | tag_id | a | b
-------------------------------+--------+---+---
 2021-07-02 13:23:30.405473+00 |      1 | 1 | 2
(1 row)

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

mxadmin=# SELECT * FROM data, data1 WHERE data.kv->'a' = data1.kv->'a';
             time              | tag_id |        kv        |             time              | tag_id |        kv
-------------------------------+--------+------------------+-------------------------------+--------+------------------
 2021-07-02 13:23:30.405473+00 |      1 | {"a": 1, "b": 2} | 2021-07-02 13:26:31.828685+00 |      1 | {"a": 1, "b": 2}
(1 row)

Примечание!
В MXKV -> и ->> имеют одинаковый эффект.

2.2 Типы данных MXKV

В предыдущем примере использовался mxkv_int4. Ниже приведено подробное описание поддерживаемых типов данных MXKV:

  1. mxkv_int4: Хранит 32-битные целые числа (int4 / int).
  2. mxkv_float4: Хранит 32-битные числа с плавающей точкой (float4 / real).
  3. mxkv_float8: Хранит 64-битные числа с плавающей точкой (float8 / float / double precision).
  4. mxkv_text: Хранит текстовые строки.

Для mxkv_float4 и mxkv_float8 можно указать количество десятичных знаков. Например:

CREATE TABLE data(
    time timestamp with time zone,
    tag_id int,
    kv mxkv_float4(2)
)
DISTRIBUTED BY (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 поддерживает только плоские структуры ключ-значение. Вложенные объекты и массивы не допускаются.
Для более глубоких технических деталей см. блог-пост MXKV.