Транзакции и запросы к YDB
Этот раздел описывает особенности реализации YQL для YDB транзакций.
Язык запросов
Основным средством создания, модификации и управления данными в YDB является декларативный язык запросов YQL. YQL — это диалект SQL, который может считаться стандартом для общения с базами данных. Кроме того, YDB поддерживает набор специальных RPC, например, для работы с древовидной схемой или для управления кластером.
Режимы транзакций
YDB поддерживает несколько режимов выполнения транзакций. По умолчанию транзакции выполняются в режиме Serializable, который предоставляет самый строгий уровень изоляции для пользовательских транзакций. Режим выполнения транзакции задаётся в настройках при её создании. Примеры для YDB SDK см. в Установка режима выполнения транзакции. Во встроенном UI режим транзакции также можно выбрать в настройках.
Поддерживаются режимы чтения-записи: Serializable (по умолчанию) и Snapshot Read-Write; режимы только для чтения: Snapshot Read-Only и Stale Read-Only. Режим Online Read-Only оставлен для совместимости со старым кодом (legacy); в новых сценариях вместо него следует использовать Snapshot Read-Only.
Serializable
Суть. Самый строгий уровень изоляции для пользовательских транзакций.
Гарантии. Результат успешно выполненных параллельных транзакций эквивалентен некоторому последовательному порядку их выполнения; для успешных транзакций нет аномалий чтений.
Snapshot Read-Write
Суть. Чтение и запись поверх одного консистентного снимка данных; по смыслу совпадает с Snapshot Isolation.
Гарантии. Все чтения в транзакции видят одно и то же состояние данных на снимке; допускается запись.
Snapshot Read-Only
Суть. Транзакция работает с целостным снимком базы на момент её старта. Гарантии на чтение данных такие же, как Snapshot Read-Write. Запись в данном режиме запрещена, за счет этого режим эффективнее, чем Snapshot Read-Write, когда необходимо только чтение данных.
Гарантии. Все чтения в транзакции видят одно и то же состояние данных на снимке; коммиты после старта транзакции не видны.
Особенности. Обеспечивает максимальную свежесть данных на момент начала транзакции, но может иметь более высокую задержку ответа из‑за необходимости формирования снимка.
Stale Read-Only
Суть. Чтения выполняются на репликах таблетки с возможным отставанием от лидера таблетки (обычно доли секунды). Режим хорошо подходит для сценария чтения по ключу, когда нужны минимальные задержки. Пользователь читает закоммиченные, но возможно устаревшие данные.
Гарантии. Низкая задержка и высокая пропускная способность за счёт чтения с реплик. Согласованность данных на уровне ключа внутри одного запроса ; между разными запросами в одной транзакции согласованность не гарантируется.
Ограничения. Нет единого снимка на всю транзакцию; согласованность между несколькими SELECT не гарантируется; возможна задержка относительно данных на лидере (данные могут быть не самыми свежими). Чтение из колоночных таблиц в этом режиме не поддерживается (см. предупреждение ниже). Дополнительные ограничения и нюансы по типам запросов см. в документации SDK для выбранного языка.
Online Read-Only
Устаревший (legacy) режим, сохранённый для совместимости. Для новых приложений при чтении без записи используйте Snapshot Read-Only. Подробности и примеры вызова в SDK по-прежнему можно найти в Online Read-Only.
Ограничение для Online Read-Only и Stale Read-Only
Эти режимы не поддерживают чтение из колоночных таблиц. Попытка чтения вызовет ошибку следующего вида:
Read from column tables is not supported in Online Read-Only or Stale Read-Only transaction modes. Use Serializable or Snapshot Read-Only mode instead.
Для транзакций с чтением из колоночных таблиц используйте:
- Serializable — режим по умолчанию;
- Snapshot Read-Only — режим чтения из консистентного снапшота.
Неявные транзакции
Логика неявных транзакций применяется при отправке одного YQL-скрипта на сервер без явного выбора режима транзакции. Типичные точки входа:
- Встроенный UI — вкладка Query на странице базы данных (форма выполнения запроса), при запуске без выбора режима транзакции в настройках.
- YDB CLI — разовая отправка скрипта командой
ydb sql. - Приложения на YDB SDK — режим ImplicitTx.
Если для запроса не задан режим транзакции, YDB автоматически управляет его поведением. Такой режим называется неявной транзакцией.
В этом режиме YDB на основе запроса определяет, выполнить его вне транзакции или обернуть в транзакцию с режимом Serializable. Режим неявной транзакции является универсальным для выполнения запроса, так как поддерживает инструкции любого вида с определённым поведением, описанным ниже.
Поведение для разных видов инструкций
-
Инструкции Data Definition Language (DDL)
DDL-инструкции (такие как CREATE TABLE, DROP TABLE и т.д.) выполняются вне транзакции. Запрос может состоять только из DDL-инструкций. При возникновении ошибки изменения, внесённые предыдущими инструкциями запроса, не откатываются. -
Инструкции Data Manipulation Language (DML)
DML-инструкции (такие как UPSERT, SELECT, UPDATE и т.д.) оборачиваются в транзакцию с режимом Serializable. Запрос может состоять только из DML-инструкций. При успешном выполнении изменения коммитятся (фиксируются), а при возникновении ошибки — откатываются. -
Инструкции пакетного изменения
Инструкции пакетного изменения (такие как BATCH UPDATE и BATCH DELETE FROM) выполняются вне транзакции. Запрос может состоять только из одной инструкции пакетного изменения. При возникновении ошибки изменения инструкции не откатываются.
Сводная таблица
| Тип инструкции | Обработка неявной транзакции | Поддержка нескольких инструкций | Откат при ошибке |
|---|---|---|---|
| DDL | Вне транзакции | Да (только DDL) | Нет |
| DML | Автоматическая транзакция (Serializable) | Да (только DML) | Да |
| Инструкции пакетного изменения | Вне транзакции | Нет | Нет |
Чтобы явно задать режим транзакции, используйте соответствующие настройки в каждой точке входа:
- Встроенный UI — выберите режим транзакции в настройках выполнения на вкладке Query.
- YDB CLI — у подкоманды
table query executeдля запросов типаdataзадайте параметр--tx-mode(по умолчаниюserializable-rw, что соответствует режиму Serializable). - YDB SDK — см. установку режима в YDB SDK.
Язык YQL
Реализованные конструкции YQL можно разделить на два класса: data definition language (DDL) и data manipulation language (DML).
Подробнее о поддерживаемых конструкциях YQL можно почитать в документации YQL.
Ниже перечислены возможности и ограничения поддержки YQL в YDB, которые могут быть неочевидны на первый взгляд и на которые стоит обратить внимание:
- Допускаются multistatement transactions, то есть транзакции, состоящие из последовательности выражений YQL. При выполнении транзакции допускается взаимодействие с клиентской программой, иначе говоря, взаимодействие клиента с базой может выглядеть следующим образом:
BEGIN; выполнить SELECT; проанализировать результаты SELECT на клиенте; ...; выполнить UPDATE; COMMIT. Стоит отметить, что если тело транзакции полностью сформировано до обращения к базе данных, то транзакция может обрабатываться эффективнее. - В YDB не поддерживается возможность смешивать DDL и DML запросы в одной транзакции. Традиционное понятие ACID транзакции применимо именно к DML запросам, то есть к запросам, которые меняют данные. DDL запросы должны быть идемпотентными, то есть повторяемы в случае ошибки. Если необходимо выполнить действие со схемой, то каждое из действий будет транзакционно, а набор действий — нет.
- Реализация YQL в YDB использует механизм Optimistic Concurrency Control. На затронутые в ходе транзакции сущности ставятся оптимистичные блокировки, при завершении транзакции проверяется, что блокировки не были инвалидированы. Оптимистичность блокировок выливается в важное для пользователя свойство — в случае конфликта выигрывает транзакция, которая завершается первой. Конкурирующие транзакции завершатся с ошибкой
Transaction locks invalidated. - Все изменения, производимые в рамках транзакции, накапливаются в памяти сервера базы данных и применяются в момент завершения транзакции. Если взятые блокировки не были инвалидированы, то все накопленные изменения применяются атомарно, если хотя бы одна блокировка была инвалидирована, то ни одно из изменений не будет применено. Описанная схема накладывает некоторые ограничения: объем изменений, осуществляемых в рамках одной транзакции, должен умещаться в оперативную память.
Для наиболее эффективного выполнения транзакций следует формировать их таким образом, чтобы в первой части транзакции выполнялись только чтения, а во второй части транзакции только модификации. Структура запроса тогда выглядит следующим образом:
SELECT ...;
....
SELECT ...;
UPDATE/REPLACE/DELETE ...;
COMMIT;
Подробнее о поддержке YQL в YDB можно прочитать в документации YQL.
Распределенные транзакции
Таблица в YDB может быть шардирована по диапазонам значений первичного ключа. Различные шарды таблицы могут обслуживаться разными серверами распределенной БД (в том числе расположенными в разных локациях), а также могут независимо друг от друга перемещаться между серверами для перебалансировки или поддержания работоспособности шарда при отказах серверов или сетевого оборудования.
Топик в YDB может быть шардирован на несколько партиций. Различные партиции топика, как и шарды таблицы, могут обслуживаться разными серверами распределенной БД.
В YDB поддерживаются распределенные транзакции. Распределенные транзакции — это транзакции, которые затрагивают более одного шарда одной или нескольких таблиц и топиков. Они требуют больше ресурсов и выполняются дольше. В то время как точечные чтения и записи могут выполняться за время до 10 мс в 99 перцентиле, распределенные транзакции, как правило, занимают от 20 до 500 мс.
Транзакции с участием топиков и таблиц
Важно
Поддерживается только для строковых таблиц. Поддержка функциональности для колоночных таблиц находится в разработке.
YDB поддерживает транзакции с участием строковых таблиц и/или топиков. Таким образом, можно транзакционно перекладывать данные из таблиц в топики и в обратном направлении, а также между топиками, чтобы данные не терялись и не дублировались даже в случае непредвиденных обстоятельств.
Подробнее о транзакционных операциях при работе с топиками см. в Транзакции с участием топиков и Работа с топиками.
Транзакции с участием строковых и колоночных таблиц
В настоящее время одновременное использование колоночных и строковых таблиц поддерживается в транзакциях, в которых данные только читаются, но не изменяются. Поддержка транзакций с возможностью модификации данных при одновременном использовании строковых и колоночных таблиц находится в разработке.
Если попытаться выполнить операцию записи в транзакции, в которой задействованы и колоночные, и строковые таблицы, транзакция завершится с ошибкой: Write transactions that use both row-oriented and column-oriented tables are disabled at current time.