Выполнение запросов

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

YDB предоставляет единый интерфейс для выполнения запросов, способный эффективно обрабатывать широкий спектр нагрузок — от высоконагруженных транзакционных OLTP-запросов до сложных аналитических OLAP-запросов. Такой подход позволяет приложениям выполнять транзакционные и аналитические запросы прозрачно, без необходимости использовать разные API для разных типов нагрузки.

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

Общий порядок работы

Далее описан пошаговый процесс обработки SQL-запросов в YDB. Знание этого процесса помогает лучше понять архитектуру и внутреннее устройство YDB.

Процесс выполнения запроса

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

  2. Начало транзакции и отправка запроса
    Используя активную сессию, приложение может начать транзакцию и сформировать запрос на языке YQL согласно своей бизнес-логике, после чего отправить его в кластер YDB.

  3. Парсинг и поиск в кеше планов
    На серверной стороне узел YDB, получивший запрос, сначала проверяет его корректность (парсинг и анализ). Затем система проверяет наличие готового физического плана выполнения в кеше запросов. Если план найден, он используется повторно.

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

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

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

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

Более подробное описание перечисленных этапов и связанных с ними понятий приведено в отдельных разделах ниже.

Сессии

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

Сессии являются долгоживущими объектами. Одна из их важных задач — эффективное распределение нагрузки: за счёт распределения сессий и связанных с ними запросов по разным узлам кластера YDB достигает высокой доступности и масштабируемости.

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

Транзакции

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

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

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

Повторные выполнения (Retries)

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

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

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

Язык запросов

Запросы для YDB пишутся на YQL — SQL-диалекте, специально адаптированным для распределённых масштабируемых баз данных. Хотя YQL не полностью совместим с ANSI SQL, он во многом сохраняет знакомый синтаксис и принципы SQL, что облегчает обучение и переход для опытных пользователей SQL. Полная справка по языку приведена в документации по YQL.

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

YQL поддерживает все основные конструкции SQL, в числе которых:

  • Язык манипулирования данными (DML): SELECT, INSERT, REPLACE, UPDATE, DELETE, UPSERT.
  • Язык определения данных (DDL): CREATE, ALTER, DROP для таблиц, индексов и других объектов схемы.
  • Соединения — все стандартные виды соединений, а также специальные типы соединений (например, LEFT SEMI, RIGHT SEMI, ANY).
  • Агрегации — группировка (GROUP BY) и оконные функции.
  • Именованные выражения для структурирования текста запроса.
  • Большое количество встроенных функций для обработки разных типов данных и решения сложных задач прямо в запросе.
  • Прагмы (pragma) и подсказки (hints) для управления планом выполнения.

Результирующие наборы

Результатом выполнения запроса в YDB может быть один или несколько результирующих наборов (result sets). Результирующий набор похож на таблицу: он содержит строки со строгой типизацией данных в каждом столбце. Строгая типизация результатов обеспечивает предсказуемость и согласованность формата выдачи.

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

Ограничения

При работе с запросами в YDB важно учитывать ряд ограничений:

  • Отсутствие схемных транзакций
    YDB не поддерживает схемные транзакции, поэтому DDL-операции (создание или изменение таблиц) нельзя объединять с DML-запросами (вставка, изменение или удаление данных) в одной транзакции или одном запросе.

  • Большие обновления и оптимистичные блокировки
    YDB применяет механизм оптимистичных блокировок. При попытке выполнить очень большие UPDATE или DELETE в рамках одной транзакции вероятность конфликтов по блокировкам сильно возрастает, делая такие операции непрактичными для реального использования.

  • Ограничения на размер транзакции
    Объём данных, записываемых в одной транзакции, ограничен. Подробности см. в разделе Ограничения при выполнении запросов.

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

Следующая