Вопросы и ответы про YDB

Общие вопросы

Что такое YDB?

YDB — это гибкий и быстрый сервис для создания распределённых отказоустойчивых NewSQL баз данных неограниченного масштаба.

Какие возможности предоставляет YDB?

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

Какая модель консистентности используется в YDB?

Для чтения данных YDB использует модель строгой консистентности (непротиворечивости) данных.

Как проектировать первичный ключ?

Чтобы правильно спроектировать первичный ключ:

  • Избегайте ситуаций, когда основная часть нагрузки приходится на один шард таблицы. При равномерной нагрузке проще достигается высокая производительность.
  • Уменьшайте количество шардов, которые могут быть задействованы чтением или записью. Чтобы достичь большей производительности, руководствуйтесь распределением: один запрос — один шард.
  • Избегайте ситуаций, при которых какая-то малая часть БД нагружена существенно больше, чем остальные части БД.

Подробнее читайте в разделе Проектирование схемы.

Как равномерно распределить нагрузку по шардам таблицы?

Чтобы равномерно распределить нагрузку по шардам таблицы и увеличить производительность, можно:

  • Изменить порядок следования компонентов ключа.
  • Использовать хеш от значений ключевых колонок в качестве первичного ключа.
  • Уменьшить количество шардов, задействованных в одном запросе.

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

Можно ли использовать NULL в ключевой колонке?

В YDB все колонки, включая ключевые, могут содержать значение NULL, однако использовать NULL в качестве значений в ключевых колонках не рекомендуется. По стандарту языка SQL (ISO/IEC 9075), значение NULL нельзя сравнивать с другими значениями, вследствие чего использование лаконичных конструкции SQL с простыми операторами сравнения может приводить, например, к тому что, строки, содержащие значение NULL, могут быть пропущены при фильтрации.

Существует ли оптимальный размер строки базы данных?

Для достижения высокой производительности не рекомендуется записывать в БД строки размером более 8 МБ и ключевые колонки размером более 2 КБ.

Как работают вторичные индексы в YDB?

Вторичные индексы в YDB — глобальные, и могут быть неуникальными. Подробнее читайте в разделе Вторичные индексы.

Как осуществляется постраничный вывод?

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

Как эффективно загружать в YDB большие объёмы данных?

Для увеличения скорости загрузки больших объёмов данных учтите следующие рекомендации:

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

Подробнее читайте в разделе Загрузка больших объёмов данных.

Как удалять устаревшие данные?

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

Есть ли в YDB поддержка ORM-клиентов?

Нет, использование ORM поверх YDB является антипаттерном.

YQL

Общие вопросы

Операции Join

Есть ли особенности в работе операции Join?

Операция Join всегда выполняется одним из двух способов:

  • Common Join
  • Index Lookup Join

Common Join

Обе таблицы (и левая, и правая части Join) посылаются на прокси. Для больших таблиц такой способ или работает медленно, или в общем случае не работает.

Index lookup Join

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

Примечание

Рекомендуется всегда использовать Index Lookup Join.

Что делать, если при запросе я получаю ошибку "Datashard: Reply size limit exceeded"?

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

Рекомендации:

  • Общая рекомендация — уменьшить обхъем данных, обрабатываемых в транзакции;
  • Если выполняется операция Join, необходимо убедиться, что операция выполняется Index lookup JOIN;
  • Если осуществляется простая выборка, нужно убедиться, что она делается по ключам, или добавить LIMIT в запрос.

Как обрабатывает оператор IN?

Выборка IN на данный момент эффективно работает только для явно заданных константных значений ключа.

Как выбрать из таблицы строчки по заданному списку ключей?

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

$keys = AsList(
    AsStruct(1ul AS Key1, "One" AS Key2),
    AsStruct(2ul AS Key1, "Three" AS Key2),
    AsStruct(4ul AS Key1, "One" AS Key2)
);

SELECT t.* FROM AS_TABLE($keys) AS k
INNER JOIN [table_items] AS t
ON t.Key1 = k.Key1 AND t.Key2 = k.Key2;

Есть ли ограничения на количество записей в константной таблице?

Явного ограничения на количество записей в константной таблице нет, но может сработать стандартное ограничение на общий размер параметров (50 Мб).

Транзакции

Почему в результате запроса выводится только 1000 строк?

1000 строк — ограничение на размер ответа. Если ответ был ограничен он будет помечен флагом Truncated. Чтобы вывести большее количество строк, воспользуйтесть постраничным выводом. Чтобы прочитать таблицу целиком, воспользуйтесь функцией readTable().

Является ли отдельный запрос атомарным?

В общем случае YQL-запросы и выражения не являются атомарными. Например, для операции UPDATE последовательно выполняются действия Read и Write, и при низких уровнях изоляции между ними данные могут быть изменены другими транзакциями. Однако все уровни изоляции кроме Serializable являются ReadOnly, так что UPDATE всегда выполняется в сериализуемой транзакции.

Что оптимальнее, несколько операций в одной транзакции, или одна операция на транзакцию?

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

Как сделать вставку только тех значений, ключей которых нет в таблице?

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

$Key = 155;
$Value = 1700;

$pair = (SELECT $Key AS Id, $Value AS Value);

$data = (
    SELECT p.Id AS Id, t.Value AS Value, p.Value AS NewValue
    FROM $pair AS p
    LEFT JOIN [test_table] AS t
    ON p.Id == t.Id
);

SELECT Id, Value, NewValue, IF (Value IS NULL, true, false) AS Inserted FROM $data;

UPSERT INTO [test_table]
SELECT Id, NewValue AS Value FROM $data
WHERE Value IS NULL;

Эту же операцию можно осуществить с помощью двух запросов:

  1. Прочитать значения по ключу;
  2. Если значение есть — выполнить COMMIT, если значения нет — выполнить UPSERT + COMMIT.

Осуществляется ли поиск по индексу для условий, содержащих операторы AND и LIKE?

Расмотрим запрос SELECT * FROM t WHERE t.shard_key = ‘my_shard_key’ AND t.key LIKE ‘some_prefix%’. Для первой части условия t.shard_key = ‘my_shard_key’ сработает поиск по индексу. Затем, к полученной выборке применится операция scan с учетом фильтром.

Ошибки

Что делать, если я часто получаю ошибку "Transaction locks invalidated"?

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

Почему возникает ошибка "Exceeded maximum allowed number of active transaction"?

В логике на клиентской стороне надо стараться держать как можно более короткие транзакции. В рамках сессии разрешено не более 10 активных транзакций. При старте транзакции нужно использовать либо коммит-флаг для автокоммита, либо явный коммит/роллбек.