Перейти к основному содержимому
Версия: 2.0.x

Primary Key table

Primary Key table использует новый механизм хранения, разработанный Selena. Его основное преимущество заключается в поддержке обновления данных в реальном времени при обеспечении эффективной производительности для сложных ad-hoc запросов. В аналитике бизнеса в реальном времени принятие решений может выиграть от Primary Key tables, которые используют самые свежие данные для анализа результатов в реальном времени, что может смягчить задержку данных в анализе данных.

Первичный ключ Primary Key table имеет ограничение UNIQUE и ограничение NOT NULL, и используется для уникальной идентификации каждой строки данных. Если значение первичного ключа новой строки данных совпадает со значением существующей строки данных в таблице, возникает нарушение ограничения UNIQUE. Тогда новая строка данных заменит существующую строку данных.

к сведению
  • Начиная с версии 3.0, ключ сортировки Primary Key table отделён от первичного ключа таблицы, и ключ сортировки может быть указан отдельно. Таким образом, повышается гибкость создания таблиц.
  • Начиная с версии 3.1, Selena shared-data clusters поддерживают создание Primary Key tables.
    • Начиная с версии 3.1.4, персистентные индексы могут быть созданы и сохранены на локальных дисках.
    • Начиная с версии 3.3.2, персистентные индексы могут быть созданы и сохранены в объектном хранилище.

Сценарии

Primary Key table может поддерживать обновление данных в реальном времени, обеспечивая при этом эффективную производительность запросов. Она подходит для следующих сценариев:

  • Потоковая передача данных в реальном времени из систем обработки транзакций в Selena. В обычных случаях системы обработки транзакций включают большое количество операций обновления и удаления в дополнение к операциям вставки. Если вам необходимо синхронизировать данные из системы обработки транзакций в Selena, мы рекомендуем создать Primary Key table. Затем вы можете использовать инструменты, такие как CDC Connectors for Apache Flink®, для синхронизации бинарных логов системы обработки транзакций в Selena. Selena использует бинарные логи для добавления, удаления и обновления данных в таблице в реальном времени. Это упрощает синхронизацию данных и обеспечивает производительность запросов в 3-10 раз выше, чем при использовании Unique Key table, которая использует стратегию Merge-On-Read. Для получения дополнительной информации см. Синхронизация в реальном времени из MySQL.
  • Объединение нескольких потоков путём выполнения частичных обновлений отдельных столбцов. В бизнес-сценариях, таких как профилирование пользователей, предпочтительно использовать плоские таблицы для повышения производительности многомерного анализа и упрощения аналитической модели, используемой аналитиками данных. Данные upstream в этих сценариях могут поступать из различных приложений, таких как приложения для шоппинга, приложения для доставки и банковские приложения, или из систем, таких как системы машинного обучения, которые выполняют вычисления для получения различных тегов и свойств пользователей. Primary Key table хорошо подходит для этих сценариев, потому что она поддерживает обновления отдельных столбцов. Каждое приложение или система может обновлять только столбцы, которые содержат данные в пределах их собственной области обслуживания, при этом пользуясь добавлением, удалением и обновлением данных в реальном времени с высокой производительностью запросов.

Как это работает

Unique Key table и Aggregate table используют стратегию Merge-On-Read. Эта стратегия делает запись данных простой и эффективной, но требует объединения нескольких версий файлов данных онлайн во время чтения данных. Более того, поскольку существует оператор Merge, предикаты и индексы не могут быть проталкнуты в базовые данные, что серьёзно влияет на производительность запросов.

Однако для баланса производительности обновлений в реальном времени и запросов структура метаданных и механизм чтения/записи в Primary Key table отличаются от таковых в других типах таблиц. Primary Key table использует стратегию Delete+Insert. Эта стратегия реализуется с использованием индекса первичного ключа и DelVector. Эта стратегия гарантирует, что во время запросов нужно читать только последнюю запись среди записей с одинаковым значением первичного ключа, что устраняет необходимость объединения нескольких версий файлов данных. Более того, предикаты и индексы могут быть проталкнуты в базовые данные, что значительно улучшает производительность запросов.

Общий процесс записи и чтения данных в Primary Key table выглядит следующим образом:

  • Запись данных достигается через внутреннее задание загрузки Selena (Loadjob), которое включает пакет операций изменения данных (Insert, Update и Delete). Selena загружает индексы первичного ключа соответствующих tablets в память. Для операций Delete Selena сначала использует индекс первичного ключа для поиска исходного местоположения (файл данных и номер строки) каждой строки данных, отмечая строку данных как удалённую в DelVector (который хранит и управляет маркерами удаления, сгенерированными во время загрузки данных). Для операций Update, помимо отметки исходной строки данных как удалённой в DelVector, Selena также записывает последнюю строку данных в новый файл данных, по сути преобразуя Update в Delete+Insert (как показано на следующем рисунке). Индекс первичного ключа также обновляется для записи нового местоположения (файл данных и номер строки) изменённой строки данных.

    pk1

  • Во время чтения данных, поскольку исторические дублирующие записи в различных файлах данных уже были отмечены как удалённые во время записи данных, необходимо читать только последнюю строку данных с одинаковым значением первичного ключа. Больше не нужно читать онлайн несколько версий файлов данных для дедупликации данных и поиска последних данных. Когда сканируются базовые файлы данных, операторы фильтрации и различные индексы помогают уменьшить затраты на сканирование (как показано на следующем рисунке). Таким образом, производительность запросов может быть значительно улучшена. По сравнению со стратегией Merge-On-Read Unique Key table, стратегия Delete+Insert Primary Key table может улучшить производительность запросов в 3-10 раз.

    pk2

Подробнее

Если вы хотите более глубоко понять, как данные записываются в Primary Key tables или читаются из них, вы можете изучить подробные процессы записи и чтения данных следующим образом:

Selena - это аналитическая база данных, использующая столбцовое хранение. В частности, tablet внутри таблицы часто содержит несколько файлов rowset, и данные каждого файла rowset фактически хранятся в файлах segment. Файлы segment организуют данные в столбцовом формате (аналогично Parquet) и являются неизменяемыми.

Когда данные, которые должны быть записаны, распределяются на узлы Executor BE, каждый узел Executor BE выполняет Loadjob. Loadjob включает пакет изменений данных и может рассматриваться как транзакция со свойствами ACID. Loadjob можно разделить на два этапа: запись и фиксация.

  1. Этап записи: Данные распределяются в соответствующий tablet на основе информации о партиционировании и bucketing. Когда tablet получает данные, данные хранятся в столбцовом формате, а затем формируется новый rowset.
  2. Этап фиксации: После успешной записи всех данных FE инициирует фиксации на всех tablets, которые задействованы. Каждая фиксация несёт номер версии, представляющий последнюю версию данных tablet. Процесс фиксации в основном включает поиск и обновление индекса первичного ключа, отметку всех изменённых данных как удалённых, создание DelVector на основе данных, отмеченных как удалённые, и генерацию метаданных для новой версии.

Во время чтения данных метаданные используются для определения того, какие rowsets необходимо прочитать на основе последней версии tablet. Когда читается файл segment в rowset, также проверяется его последняя версия DelVector, что может гарантировать, что нужно читать только последние данные и избежать чтения старых данных с одинаковым значением первичного ключа. Кроме того, операторы фильтрации, проталкиваемые в слой Scan, могут напрямую использовать различные индексы для уменьшения затрат на сканирование.

  • Tablet: Таблица делится на несколько tablets на основе механизмов партиционирования и bucketing. Это фактическая физическая единица хранения, распределённая в виде реплик на разных BE.

    pk3

  • Metadata: Метаданные хранят историю версий tablet и информацию о каждой версии (например, какие rowsets включены). Этап фиксации каждого Loadjob или compaction генерирует новую версию.

    pk4

  • Индекс первичного ключа: Индекс первичного ключа хранит отображение между строками данных, идентифицированными значениями первичного ключа, и местоположениями этих строк данных. Он реализован как HashMap, где ключи представляют закодированные значения первичного ключа, а значения представляют местоположения строк данных (включая rowset_id, segment_id и rowid). Обычно индекс первичного ключа используется только во время записи данных для поиска rowset и строки, в которой находится каждая строка данных, идентифицированная определённым значением первичного ключа.

  • DelVector: DelVector хранит маркеры удаления для каждого файла segment (столбцового файла) в каждом rowset.

  • Rowset: Rowset - это логическая концепция, которая хранит набор данных из пакета изменений данных в tablet.

  • Segment: Данные в rowset фактически сегментированы и хранятся в одном или нескольких файлах segment (столбцовых файлах). Каждый файл segment содержит значения столбцов и информацию об индексах, связанных со столбцами.

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

Создание Primary Key table

Вам просто нужно определить первичный ключ в операторе CREATE TABLE, чтобы создать Primary Key table. Пример:

CREATE TABLE orders1 (
order_id bigint NOT NULL,
dt date NOT NULL,
user_id INT NOT NULL,
good_id INT NOT NULL,
cnt int NOT NULL,
revenue int NOT NULL
)
PRIMARY KEY (order_id)
DISTRIBUTED BY HASH (order_id)
;
к сведению

Поскольку Primary Key table поддерживает только hash bucketing в качестве стратегии bucketing, вам также необходимо определить ключ hash bucketing с помощью DISTRIBUTED BY HASH ().

Однако в реальных бизнес-сценариях при создании Primary Key table часто используются дополнительные функции, такие как распределение данных и ключ сортировки, для ускорения запросов и более эффективного управления данными.

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

Начиная с версии 3.0, ключ сортировки Primary Key table отделён от первичного ключа таблицы. Поэтому вы можете выбрать столбцы, часто используемые в качестве условий фильтрации запросов, для формирования ключа сортировки. Например, если вы часто запрашиваете эффективность продаж товаров на основе комбинации двух измерений, дата заказа и продавец, вы можете указать ключ сортировки как dt и merchant_id с помощью предложения ORDER BY (dt,merchant_id).

Обратите внимание, что если вы используете стратегии распределения данных, Primary Key table в настоящее время требует, чтобы первичный ключ включал столбцы партиционирования и bucketing. Например, стратегия распределения данных использует dt в качестве столбца партиционирования и merchant_id в качестве столбца hash bucketing. Первичный ключ также должен включать dt и merchant_id.

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

CREATE TABLE orders2 (
order_id bigint NOT NULL,
dt date NOT NULL,
merchant_id int NOT NULL,
user_id int NOT NULL,
good_id int NOT NULL,
good_name string NOT NULL,
price int NOT NULL,
cnt int NOT NULL,
revenue int NOT NULL,
state tinyint NOT NULL
)
PRIMARY KEY (order_id,dt,merchant_id)
PARTITION BY date_trunc('day', dt)
DISTRIBUTED BY HASH (merchant_id)
ORDER BY (dt,merchant_id)
PROPERTIES (
"enable_persistent_index" = "true"
);

Первичный ключ

Первичный ключ таблицы используется для уникальной идентификации каждой строки в этой таблице. Один или несколько столбцов, составляющих первичный ключ, определяются в PRIMARY KEY и имеют ограничение UNIQUE и ограничение NOT NULL.

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

  • В операторе CREATE TABLE столбцы первичного ключа должны быть определены перед другими столбцами.
  • Столбцы первичного ключа должны включать столбцы партиционирования и bucketing.
  • Столбцы первичного ключа поддерживают следующие типы данных: числовые (включая целые числа и BOOLEAN), строковые и дата (DATE и DATETIME).
  • По умолчанию максимальная длина закодированного значения первичного ключа составляет 128 байт.
  • Первичный ключ нельзя изменить после создания таблицы.
  • В целях обеспечения согласованности данных значения первичного ключа не могут быть обновлены.

Индекс первичного ключа

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

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

Если диск является SSD, рекомендуется установить значение true. Если диск является HDD и частота загрузки невысока, вы также можете установить значение true.

Начиная с версии 3.1.4, Primary Key tables, созданные в Selena shared-data clusters, поддерживают сохранение индекса на локальных дисках. А начиная с версии 3.3.2 Selena shared-data clusters дополнительно поддерживают сохранение индекса в объектном хранилище. Вы можете включить эту функцию, установив свойство таблицы persistent_index_type в CLOUD_NATIVE.

Ключ сортировки

Начиная с версии 3.0, Primary Key table отделяет ключ сортировки от Primary Key. Ключ сортировки состоит из столбцов, определённых в ORDER BY, и может состоять из любой комбинации столбцов, при условии, что тип данных столбцов соответствует требованиям ключа сортировки.

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

к сведению
  • Если указан ключ сортировки, префиксный индекс строится на основе ключа сортировки. Если ключ сортировки не указан, префиксный индекс строится на основе Primary Key.
  • После создания таблицы вы можете использовать ALTER TABLE ... ORDER BY ... для изменения ключа сортировки. Удаление ключа сортировки не поддерживается, а изменение типов данных столбцов сортировки не поддерживается.

Что ещё

  • Для загрузки данных в созданную таблицу вы можете обратиться к Обзор загрузки, чтобы выбрать подходящий вариант загрузки.
  • Если вам необходимо изменить данные в Primary Key table, вы можете обратиться к изменение данных через загрузку или использовать DML (INSERT, UPDATE и DELETE).
  • Если вы хотите дополнительно ускорить запросы, вы можете обратиться к Ускорение запросов.
  • Если вам необходимо изменить схему таблицы, вы можете обратиться к ALTER TABLE.
  • Столбец AUTO_INCREMENT может использоваться в качестве Primary Key.