Оптимизация запросов, использующих именованные выражения

В этой статье описывается, как оптимизировать повторное использование именованных выражений в запросе.

В языке запросов Kusto можно привязать имена к сложным выражениям несколькими способами:

При ссылке на эти именованные выражения в запросе выполняются следующие действия:

  1. Происходит вычисление в именованном выражении. В результате вычисления создается скалярное или табличное значение.
  2. Именованное выражение заменяется вычисленным значением.

Если одно и то же связанное имя используется несколько раз, базовое вычисление будет повторяться несколько раз. В каких случаях это может стать проблемой?

  • Когда вычисления потребляют много ресурсов и используются многократно.
  • Если вычисление не детерминировано, но запрос предполагает, что все вызовы возвращают одно и то же значение.

Меры по снижению риска

Чтобы избежать этих проблем, можно материализовать результаты вычисления в памяти при выполнении запроса. В зависимости от способа определения именованного вычисления будут использоваться разные стратегии материализации:

табличные функции.

Используйте следующие стратегии для табличных функций:

  • Операторы let и параметры функции: используйте функцию materialize().
  • Оператор as: присвойте указанию hint.materialized значение true.

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

Примечание

Как правило, таблицы не отсортированы, поэтому любая ссылка на таблицу в запросе не является детерминированной по определению.

Поведение без использования функции материализации

range x from 1 to 100 step 1
| sample 1
| as T
| union T

Выходные данные

x
63
92

Поведение с использованием функции материализации

range x from 1 to 100 step 1
| sample 1
| as hint.materialized=true T
| union T

Выходные данные

x
95
95

Скалярные функции

Недетерминированные скалярные функции можно принудительно вычислить один раз с помощью toscalar().

Например, следующий запрос использует недетерминированную функцию rand():

let x = () {rand(1000)};
let y = () {toscalar(rand(1000))};
print x, x, y, y

Выходные данные

print_0 print_1 print_2 print_3
166 137 70 70