Перейти к основному содержимому

Таблица Primary Key

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

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

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

Сценарии

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

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

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

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

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

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

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

    pk1

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

    pk2

Больше деталей

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

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

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

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

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

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

    pk3

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

    pk4

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

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

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

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

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

Создание таблицы Primary Key

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

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 поддерживает только хеш-разбиение как стратегию разбиения, вам также нужно определить ключ хеш-разбиения, используя DISTRIBUTED BY HASH ().

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

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

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

Обратите внимание, что если вы используете стратегии распределения данных, таблица Primary Key в настоящее время требует, чтобы первичный ключ включал столбцы разделения и разбиения. Например, стратегия распределения данных использует dt как столбец разделения и merchant_id как столбец хеш-разбиения. Первичный ключ также должен включать 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 столбцы первичного ключа должны быть определены перед другими столбцами.
  • Столбцы первичного ключа должны включать столбцы разделения и разбиения.
  • Столбцы первичного ключа поддерживают следующие типы данных: числовые (включая целые числа и BOOLEAN), строковые и даты (DATE и DATETIME).
  • По умолчанию максимальная длина закодированного значения первичного ключа составляет 128 байт.
  • Первичный ключ нельзя изменить после создания таблицы.
  • Для целей согласованности данных значения первичного ключа не могут быть обновлены.

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

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

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

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

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

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

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

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

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

Что ещё

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