Этапы исполнения запроса
YQL относится к сильно типизированным (strongly typed) языкам программирования. Это, в частности, означает следующее — перед тем, как YQL запрос начнёт выполняться, он должен быть типизирован (т. е. для каждого узла в графе вычислений должен быть вычислен его тип). При нажатии на кнопку Validate в веб-интерфейсе как раз и происходит типизация.
Например, запрос
SELECT key + 1 AS new_key FROM T;
типизируется следующим образом (тут есть некоторые упрощения):
- Загружаются метаданные таблицы
T
, из которых выясняется, что тип колонкиkey
— Uint32. - Тип литерала всегда известен: тип 1 — Int32.
- Вычисляется тип операции
+
по типам аргументов. Для аргументов Int32,Uint32 результат — Int32. - В результате получается, что тип запроса — список структур с одним Int32 элементом, а именно
List<Struct<new_key:Int32>>
.
Однако YQL поддерживает и более сложные для типизации случаи, когда тип запроса зависит от значений некоторых выражений, причём эти значения, в свою очередь, могут зависеть от содержимого таблиц. Типичный пример:
$from = "2022-02-01";
$to = SELECT MAX(dt) FROM T1;
INSERT INTO Result
SELECT * FROM RANGE(Dir, $from, $to);
Для того чтобы вывести тип RANGE (т. е. вывести общий тип для таблиц), следует посчитать значение $to
.
Другой пример:
$cols = SELECT AGGREGATE_LIST(DISTINCT name) FROM T1 WHERE <condition>; -- динамически формируем интересный нам список колонок
-- выбираем колонки из списка
SELECT * FROM (SELECT ChooseMembers(TableRow(), $cols) FROM T2) FLATTEN COLUMNS;
Для того чтобы типизировать ChooseMembers, необходимо вычислить значение (не тип) $cols
.
Таким образом, можно сделать выводы:
- Некоторые запросы на YQL требуют вычислений для типизации.
- Иногда эти вычисления требуют чтений из таблиц.
Для типизации подобных запросов в YQL есть отдельная Evaluation стадия, на которой и производятся необходимые вычисления.
Однако у вычислений на этой стадии есть ограничения. Главное из них — суммарный размер таблиц, от которых зависит Evaluation стадия, ограничен. Ограничение по умолчанию составляет 1Мб, но его можно расширить до 10Мб с помощью прагмы yt.EvaluationTableSizeLimit.
Причина таких ограничений — стремление избежать долгой Evaluation стадии, на которой ещё нельзя показать план выполнения запроса и после которой всё ещё возможны пользовательские ошибки типизации. Обидно запустить расчёт на несколько часов, после чего увидеть, что запрос упал с ошибкой 'No such column'.
Единственный способ обойти это ограничение — разбить запрос на два. В первом запросе считается evaluation часть и записывается в таблицу. Второй запрос уже будет зависеть от этой (маленькой по размерам) таблицы.