Таблица

Таблица — это реляционная таблица, содержащая набор связанных данных, состоящий из строк и столбцов. Таблицы описывают сущности. Например, статья в блоге может быть представлена таблицей article со столбцами: id, date_create, title, author и т.д. Строки содержат данные, а столбцы определяют типы данных. Например, столбец id не может быть пустым (NOT NULL) и должен содержать только уникальные целочисленные значения. Запись в YQL может выглядеть так:

CREATE TABLE article (
    id Int64 NOT NULL,
    date_create Date,
    author String,
    title String,
    PRIMARY KEY (id)
)

YDB поддерживает создание строковых и колоночных таблиц. Основное их отличие — в области применения и формате хранения данных на жестком диске. Для строковых таблиц данные хранятся последовательно в виде строк, а для колоночных — в виде столбцов. У каждого типа таблиц свое предназначение.

Строковые таблицы

Строковые таблицы хорошо подходят для транзакционных запросов, которые генерируют Online Transaction Processing (OLTP) системы, например, бекэнды сервисов погоды или интернет-магазинов. Строковые таблицы предоставляют эффективный доступ к большому количеству столбцов одновременно. Поиск по строковым таблицам работает очень быстро, за счет использования индексов.

Индекс — это структура данных, которая увеличивает скорость операций извлечения данных на основе одного или нескольких столбцов. Это аналог индекса в книге: вместо того чтобы просматривать каждую страницу книги, чтобы найти нужный раздел, вы можете обратиться к индексу в конце книги и быстро перейти к нужной странице.

Когда выполняется запрос на основе столбца (или столбцов), по которому (которым) создан индекс, СУБД может использовать этот индекс, чтобы быстро найти соответствующие строки, минуя полный перебор всех данных. Например, если у вас есть индекс на столбце "author", и вы ищете все статьи, написанные автором "Gray", СУБД использует индекс для быстрого нахождения всех строк с этой фамилией.

Создать строковую таблицу можно через web-интерфейс YDB, с помощью CLI или SDK. Вне зависимости от способа взаимодействия с YDB стоит помнить об общем правиле создания строковой таблицы: таблица должна иметь минимум одну ключевую колонку, при этом допускается создание таблицы, состоящий только из ключевых колонок.

По умолчанию при создании строковой таблицы все столбцы опциональны и могут иметь значения NULL, такое поведение можно изменить и задать условия NOT NULL для ключевых колонок, которые входят в состав первичного ключа. Первичные ключи уникальны, и строковые таблицы всегда упорядочены по ключу. Это означает, что точечное чтение по ключу, а также диапазонные запросы по ключу или префиксу ключа выполняются эффективно (фактически используя индекс). Допускается создание таблицы, состоящей только из ключевых столбцов. К выбору ключа нужно подходить аккуратно, поэтому рекомендуем ознакомиться со статьей: "Выбор первичного ключа для максимальной производительности".

Партиционирование строковой таблицы

Строковая таблица в БД может быть партиционированна по диапазонам значений первичного ключа. Каждая партиция таблицы отвечает за свой диапазон первичных ключей. Диапазоны ключей, обслуживаемых разными партициями, не пересекаются. Различные партиции таблицы могут обслуживаться разными серверами распределенной БД (в том числе расположенными в разных локациях), а также могут независимо друг от друга перемещаться между серверами для перебалансировки или поддержания работоспособности партиции при отказах серверов или сетевого оборудования.

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

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

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

Независимо от значения параметра AUTO_PARTITIONING_PARTITION_SIZE_MB, YDB выполняет разделение и объединение партиций, ориентируясь на размер в 2000 MB. При этом YDB не ограничивает пользовательские настройки, а работает параллельно с ними. Например, если задать размер партиции 100 MB и ограничение на 10 партиций, то, когда у таблицы станет 10 партиций по 100 MB, она перестанет делиться, и размер партиций начнет увеличиваться. Когда размер какой-либо партиции превысит 2000 MB, она разделится, и в таблице станет 11 партиций. Если размер двух соседних партиций уменьшится до 1000 MB, они объединятся, и в таблице снова станет 10 партиций.

Помимо автоматического разделения, предоставляется возможность создать пустую таблицу с заданным количеством партиций. При этом можно вручную задать точные границы разделения ключей по партициям или указать равномерное распределение на заданное количество партиций. В последнем случае границы будут созданы по первой компоненте первичного ключа. Равномерное распределение можно указать для таблиц, у которых первая компонента первичного ключа является целым числом с типом данных Uint64 или Uint32.

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

Характерное время операции разделения или объединения составляет около 500 мс. В течение этого времени данные, вовлечённые в операцию, становятся кратковременно недоступны для чтения и записи. Специализированные методы-обёртки в YDB SDK автоматически выполняют повторные попытки при обнаружении, что партиция находится в состоянии разделения или объединения, не поднимая эту информацию до уровня приложения. Важно отметить, что если система по каким-либо причинам перегружена (например, из-за нехватки CPU или пропускной способности выделенных дисковых ресурсов), операции разделения и объединения могут занимать больше времени.

В схеме данных определяются следующие параметры партиционирования таблицы:

AUTO_PARTITIONING_BY_SIZE

  • Тип: Enum (ENABLED, DISABLED).
  • Значение по умолчанию: ENABLED.

Режим автоматического партиционирования по размеру партиции. Если размер партиции превысил значение, заданное параметром AUTO_PARTITIONING_PARTITION_SIZE_MB, то она встает в очередь на разделение (split). Если суммарный размер двух или более соседних партиции меньше 50% от значения параметра AUTO_PARTITIONING_PARTITION_SIZE_MB, то они встают в очередь на объединение (merge).

AUTO_PARTITIONING_BY_LOAD

  • Тип: Enum (ENABLED, DISABLED).
  • Значение по умолчанию: DISABLED.

Режим автоматического партиционирования по нагрузке. Если в течение нескольких десятков секунд партиция потребляет более 50% CPU, то он ставится в очередь на разделение (split). Если в течение часа суммарная нагрузка на два или более соседних партиций утилизировала менее 35% одного ядра CPU, то они ставятся в очередь на объединение (merge).

Выполнение операций разделения или объединения само по себе утилизирует CPU, и занимает время. Поэтому, при работе с плавающей нагрузкой рекомендуется вместе с включением данного режима устанавливать отличное от 1 значение параметра минимального количества партиций AUTO_PARTITIONING_MIN_PARTITIONS_COUNT, чтобы спады нагрузки не приводили к снижению количества партиций ниже необходимого, и не было потребности их заново делить при появлении нагрузки.

При выборе минимального количества партиций имеет смысл руководствоваться соображениями, что одна партиция таблицы может находиться только на одном сервере и использовать не более 1 ядра CPU для операций изменения данных. Исходя из этого, для таблицы на которой может ожидаться высокая нагрузка, можно указывать минимальное количество партиций не менее количества узлов (серверов), а лучше порядка количества ядер CPU, выделенных базе.

AUTO_PARTITIONING_PARTITION_SIZE_MB

  • Тип: Uint64.
  • Значение по умолчанию: 2000 MB ( 2 ГБ ).

Желаемый порог размера партиции в мегабайтах. Рекомендуемые значения варьируются от 10 MB до 2000 MB. Если этот порог превышается, партиция может быть разделена.
Указанное значение служит лишь рекомендацией для разделения. Возможны ситуации, когда разделение не произойдёт, даже если указанный размер превышен.
Эта настройка применяется, когда включён режим AUTO_PARTITIONING_BY_SIZE.

AUTO_PARTITIONING_MIN_PARTITIONS_COUNT

  • Тип: Uint64.
  • Значение по умолчанию: 1.

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

AUTO_PARTITIONING_MAX_PARTITIONS_COUNT

  • Тип: Uint64.
  • Значение по умолчанию: 50.

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

UNIFORM_PARTITIONS

  • Тип: Uint64.
  • Значение по умолчанию: не применимо.

Количество партиций для равномерного начального разделения таблицы. Первая колонка первичного ключа должна иметь тип Uint64 или Uint32. Созданная таблица сразу будет разделена на указанное количество партиций.

При включенном автоматическом партиционировании необходимо также не забыть установить корректное значение параметра AUTO_PARTITIONING_MIN_PARTITIONS_COUNT, чтобы все партиции не объединились в одну сразу после создания таблицы.

PARTITION_AT_KEYS

  • Тип: Expression.
  • Значение по умолчанию: не применимо.

Граничные значения ключей для начального разделения на партиции. Представляется списком граничных значений, разделенных запятыми и обрамленными в скобки. Каждое граничное значение может быть либо набором значений ключевых колонок (также разделенных запятыми и обрамленными в скобки), либо единичным значением, если указываются только значения первой ключевой колонки. Примеры: (100, 1000), ((100, "abc"), (1000, "cde")).

При включенном автоматическом партиционировании необходимо также не забыть установить корректное значение параметра AUTO_PARTITIONING_MIN_PARTITIONS_COUNT, чтобы все партиции не объединились в одну сразу после создания таблицы.

Чтение с реплик

При выполнении запросов в YDB фактическое выполнение запроса к каждой партиции осуществляется в единой точке, обслуживающей протокол распределенных транзакций. Но благодаря хранению данных на разделяемом хранилище возможен запуск одного или нескольких фолловеров партиции, без выделения дополнительного места на сторадже — данные уже хранятся реплицированно и возможно обслуживание более одного читателя (но писатель при этом все еще в каждый момент строго один).

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

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

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

Имя параметра Описание Тип Допустимые значения Возможность
изменения
Возможность
сброса
READ_REPLICAS_SETTINGS PER_AZ означает использование указанного количества реплик в каждом AZ, ANY_AZ — во всех AZ суммарно. String "PER_AZ:<count>", "ANY_AZ:<count>" где <count> — число реплик Да Нет

Внутреннее состояние каждого из фолловеров восстанавливается в точности по состоянию лидера и полностью консистентно.

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

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

Автоматическое удаление устаревших данных (TTL)

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

Имя параметра Тип Допустимые значения Возможность
изменения
Возможность
сброса
TTL Expression Interval("<literal>") ON <column> [AS <unit>] Да Да

Где <unit> — единица измерения, указывается только для колонок с числовым типом:

  • SECONDS;
  • MILLISECONDS;
  • MICROSECONDS;
  • NANOSECONDS.

Подробнее об удалении устаревших данных читайте в разделе Time to Live (TTL).

Переименование

YDB позволяет переименовать существующую таблицу, переместить ее в другую директорию этой же базы данных, а также заменить одну таблицу другой, при этом данные заменяемой таблицы будут удалены. При выполнении операций изменяются только метаданные таблицы, например ее путь и имя. Данные таблицы не переносятся и не перезаписываются.

Операции выполняются изолированно, внешний процесс видит только два состояния таблицы: до и после выполнения операции. Это важно, например, при замене таблицы — данные заменяемой таблицы удаляются в той же транзакции, в которой заменяющая таблица переименовывается. Во время выполнения операции замены возможны ошибки запросов к заменяемой таблице с retryable-статусами.

Скорость выполнения переименования определяется типом дата-транзакций, которые выполняются в данный момент на таблице, и не зависит от количества данных в таблице.

Фильтр Блума

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

Имя параметра Тип Допустимые значения Возможность
изменения
Возможность
сброса
KEY_BLOOM_FILTER Enum ENABLED, DISABLED Да Нет

Группы колонок

YDB позволяет группировать колонки в таблице для оптимизации их хранения и использования. Механизм групп колонок позволяет увеличить производительность операций неполного чтения строк путем разделения хранения колонок таблицы на насколько групп. Наиболее часто используемый сценарий — организация хранения редко используемых атрибутов в отдельной группе колонок (и, возможно, с использованием сжатия и на более медленных устройствах хранения данных).

У каждой группы колонок есть собственное имя, уникальное в рамках таблицы. Состав групп колонок устанавливается при создании таблицы, а также может быть изменен позднее. Удаление групп колонок из существующей таблицы не предусмотрено.

Группа колонок может содержать произвольное число колонок своей таблицы, в том числе не содержать ни одной. Каждая колонка таблицы принадлежит одной, и только одной группе колонок (группы колонок не пересекаются). Принадлежность колонок группам устанавливается при создании таблицы, но может быть изменена позднее.

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

Для группы колонок устанавливаются атрибуты, влияющие на хранение данных:

  • используемый тип устройств хранения данных (SSD или HDD, доступность типов зависит от конфигурации кластера YDB);
  • режим сжатия данных (без сжатия или сжатие алгоритмом LZ4).

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

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

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

Пользовательские атрибуты

Пользовательские атрибуты позволяют добавлять произвольную информацию к метаданным таблицы. Эта информация не интерпретируется сервером, однако может быть интерпретирована клиентом БД (человеком или, чаще, программой).

Атрибуты задаются в виде пары ключ-значение. Ключом и значением атрибута может быть только строка или тип, который может быть представлен строкой (например, используя base64-кодирование).

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

  • длина ключа — 1–100 байт;
  • длина значения — 1–4096 байт;
  • максимальный общий размер атрибутов (сумма длин всех ключей и значений) — 10240 байт.

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

Колоночные таблицы

Важно

Колоночные таблицы YDB доступны в режиме Preview.

Колоночные таблицы YDB хранят данные каждого столбца отдельно (независимо) от других столбцов. Такой принцип хранения данных оптимизирован для работы с Online Analytical Processing-нагрузками (OLAP), так как при выполнении запроса считываются только те столбцы, которые непосредственно участвуют в запросе. Еще один плюс такого подхода — высокая степень сжатия данных, так как в столбцах зачастую хранятся повторяющиеся или близкие данные. Минусом является то, что выполнение операций над строками становится более затратным.

На данный момент основной сценарий использования колоночных таблиц YDB — запись данных с возрастающим первичным ключом (например, время события), анализ этих данных и удаление устаревших данных по TTL. Оптимальным способом добавления данных в колоночные таблицы YDB является пакетная запись, выполняемая блоками в единицы МБ. Вставка пакетов данных производится атомарно: данные будут записаны или во все партиции, или ни в одну.

В большинстве случаев работа с колоночными таблицами YDB аналогична работе со строковыми, но есть и отличия:

  • В качестве первичного ключа можно использовать только NOT NULL колонки.

  • Данные партицируются не по первичному ключу, а по Hash от колонок партицирования.

  • В колоночных таблицах поддерживается ограниченный набор типов данных:

    • Доступно и в первичном ключе и в остальных колонках: Date, Datetime, Timestamp, Int32, Int64, Uint8, Uint16, Uint32, Uint64, Utf8, String;
    • Доступно только в колонках, не входящих в первичный ключ: Bool, Decimal, Double, Float, Int8, Int16, Interval, JsonDocument, Json, Uuid, Yson.

Повторим создание таблицы article, на этот раз в колоночной форме, с помощью следующей YQL-команды:

CREATE TABLE article_column_table (
    id Int64 NOT NULL,
    author String,
    title String,
    PRIMARY KEY (id)
)
WITH (STORE = COLUMN);

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

  • Чтение с реплик.
  • Вторичные индексы.
  • Фильтры Блума.
  • Change Data Capture.
  • Переименование таблиц.
  • Пользовательские атрибуты таблиц.
  • Изменение списка колонок данных.
  • Добавление данных в колоночные таблицы с помощью SQL-оператора INSERT.
  • Удаление данных из колоночных таблиц с помощью SQL-оператора DELETE. Фактически, удаление возможно только по истечению TTL времени хранения данных.

Партицирование колоночной таблицы

В отличие от строковых таблиц YDB, колоночные таблицы партицируют данные не по первичным ключам, а по специально выделенным ключам — ключам партицирования. Ключи партицирования являются подмножеством первичных ключей таблицы.

В отличие от партицирования данных в строковых таблицах YDB, партицирование данных для колоночных таблиц выполняется не по значениям ключей, а по hash-значениям от ключей, что позволяет равномерно распределить данные во все существующие партиции. Такое партицирование позволяет избежать хотспотов при вставке и ускоряет аналитические запросы, обрабатывающие (считывающие) большие объемы данных.

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

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

AUTO_PARTITIONING_MIN_PARTITIONS_COUNT определяет минимальное физическое количество партиций для хранения данных.

Тип: Uint64.

Значение по умолчанию: 64.

С учетом, что остальные параметры партицирования игнорируются, это же значение определяет и верхнее число партиций.

Предыдущая