Скан запросы (Scan Query) в YDB

Скан запросы (Scan Queries) — это отдельный интерфейс доступа к данным, предназначенный в первую очередь для выполнения аналитических ad-hoc запросов над базой данных.

Данный способ исполнения запросов обладает следующими отличительными свойствами:

  • Это только Read-Only запросы.
  • В режиме SERIALIZABLE_RW берется снапшот данных, над которым в дальнейшем и происходит вся работа. В результате влияние на поток OLTP-транзакций минимальное (только снятие снапшота).
  • Результат запроса — это стрим данных (grpc stream). Таким образом, у скан запросов нет лимита на количество строк в результате.
  • Из-за высоких накладных расходов подходит только для ad-hoc запросов.

Через интерфейс Scan Queries можно выполнять запросы к системным таблицам.

На текущий момент скан запросы не могут считаться полноценным способом выполнения OLAP-запросов, поскольку они обладают рядом технических ограничений (которые со временем будут сняты):

  • Длительность запроса ограничена 5 минутами.
  • Многие операции (включая сортировку) выполняются целиком в памяти, поэтому на сложных запросах можно получить ошибку нехватки ресурсов.
  • Для джойнов на текущий момент используется только одна стратегия — MapJoin (aka Broadcast Join), где «правая» таблица конвертируется в карту, поэтому она должна быть не более единиц гигабайт.
  • Не поддерживается prepared-форма, т.е. на каждый вызов происходит компиляция запроса.
  • Нет оптимизаций под точечные чтения и чтения небольших диапазонов данных.
  • В SDK не поддерживается автоматический retry.

Примечание

Несмотря на то, что Scan Queries явно не мешают выполнению OLTP-транзакций, они все же используют общие ресурсы базы: СPU, память, диск, сеть. Поэтому выполнение тяжелых запросов может привести к голоданию по ресурсам, что скажется на производительности всей базы.

Как воспользоваться

Как и другие виды запросов, Scan Queries доступны через CLI и SDK.

C++ SDK

Для запуска запроса через механизм Scan Queries предназначены 2 метода в классе Ydb::TTableClient:

class TTableClient {
    ...
    TAsyncScanQueryPartIterator StreamExecuteScanQuery(const TString& query,
        const TStreamExecScanQuerySettings& settings = TStreamExecScanQuerySettings());

    TAsyncScanQueryPartIterator StreamExecuteScanQuery(const TString& query, const TParams& params,
        const TStreamExecScanQuerySettings& settings = TStreamExecScanQuerySettings());
    ...
};