#azure-application-insights #azure-data-explorer #kql
#azure-application-insights #azure-data-explorer #kql
Вопрос:
Я пытаюсь создать запрос Kusto для измерения «собственной» продолжительности запросов (вычитая длительности зависимостей). Однако я не могу понять, как решить это с помощью чистого запроса Kusto.
Чтобы лучше понять, чего можно было бы ожидать, ниже приведен пример:
Представление высокого уровня (где R — запрос, а Dx — зависимости)
R =============================== (31ms)
D1 ******* (7ms)
D2 ******** (8ms)
D3 ****** (6ms)
D4 ** (2ms)
D5 **** (4ms)
Proj ==*************======******====
D1
перекрываетсяD2
в течение 2 мсD5
иD4
не следует принимать во внимание, что они полностью перекрываются другими зависимостямиProj
является проекцией потенциального промежуточного шага, на котором отображаются только значимые сегменты зависимостей
Учитывая следующий набор данных тестового стенда
let reqs = datatable (timestamp: datetime, id:string, duration: real)
[
datetime("2020-12-15T08:00:00.000Z"), "r1", 31 // R
];
let deps = datatable (timestamp: datetime, operation_ParentId:string, duration: real)
[
datetime("2020-12-15T08:00:00.002Z"), "r1", 7, // D1
datetime("2020-12-15T08:00:00.007Z"), "r1", 8, // D2
datetime("2020-12-15T08:00:00.021Z"), "r1", 6, // D3
datetime("2020-12-15T08:00:00.023Z"), "r1", 2, // D4
datetime("2020-12-15T08:00:00.006Z"), "r1", 4, // D5
];
В этом конкретном случае запрос Kusto, соединяющий две таблицы данных, должен иметь возможность извлекать 12
(продолжительность запроса, удаление всех зависимостей), т. Е..
Expected total duration = 31 - (7 8 - 2) - (6) = 12
Любая помощь в продвижении вперед была бы с благодарностью <3
Ответ №1:
Мне удалось решить это с помощью этого использования row_window_session()
. Это оконная функция. Подробнее об этом можно прочитать в обзоре функций окна.
Решение таково:
let reqs = datatable (timestamp: datetime, operation_ParentId:string, duration: real)
[
datetime("2020-12-15T08:00:00.000Z"), "r1", 31 // R
];
let deps = datatable (timestamp: datetime, operation_ParentId:string, duration: real)
[
datetime("2020-12-15T08:00:00.002Z"), "r1", 7, // D1
datetime("2020-12-15T08:00:00.007Z"), "r1", 8, // D2
datetime("2020-12-15T08:00:00.021Z"), "r1", 6, // D3
datetime("2020-12-15T08:00:00.006Z"), "r1", 4, // D5
datetime("2020-12-15T08:00:00.023Z"), "r1", 2, // D4
];
deps
| extend endTime = timestamp totimespan(duration * 10000)
| sort by timestamp asc
| serialize | extend SessionStarted = row_window_session(timestamp, 1h, 1h, timestamp > prev(endTime))
| summarize max(endTime) by operation_ParentId, SessionStarted
| extend diff = max_endTime - SessionStarted
| summarize todouble(sum(diff)) by operation_ParentId
| join reqs on operation_ParentId
| extend diff = duration - sum_diff / 10000
| project diff
Идея здесь состоит в том, чтобы отсортировать записи по времени открытия, и пока следующее предыдущее время окончания позже текущего времени начала, мы не открываем новый сеанс. Давайте объясним каждую строку этого запроса, чтобы понять, как это делается:
- Вычислите на
endTime
основе продолжительности. Чтобы нормализовать данные, я умножу продолжительность на 10000:| extend endTime = timestamp totimespan(duration * 10000)
- Сортировка по времени запуска:
| sort by timestamp asc
- Это ключ к этому решению. Он рассчитывается по
timestamp
столбцу. Следующие два параметра — это ограничения на запуск новых сегментов. Поскольку мы не хотим запечатывать ведро в зависимости от прошедшего времени, я предоставил 1 час, который не попадет в этот ввод. Четвертый аргумент помогает нам создать новый сеанс на основе данных. Пока строк будет большеtimestamp > prev(endTime)
, они будут иметь одинаковое время начала.| serialize | extend SessionStarted = row_window_session(timestamp, 1h, 1h, timestamp > prev(endTime))
- Теперь у нас есть несколько строк для начала сеанса. Поэтому мы хотим сохранить только самое последнее время для каждого сеанса. Мы также продолжим
operation_ParentId
позже присоединиться к этому ключу:| summarize max(endTime) by operation_ParentId, SessionStarted
- Вычислите время каждого сеанса:
| extend diff = max_endTime - SessionStarted
- Суммируйте все время сеанса:
| summarize todouble(sum(diff)) by operation_ParentId
- Присоединяйтесь
req
, чтобы узнать общее время начала:| join reqs on operation_ParentId
- Вычислите разницу между общим временем и временем сеанса. Ненормализовать данные:
| extend diff = duration - sum_diff / 10000
- Спроецируйте конечный результат:
| project diff
Вы можете найти этот запрос, выполняемый в открытой базе данных Kusto Samples.
Сказав это, обратите внимание, что это линейная операция. Это означает, что если есть 2 следующих сегмента, которые должны находиться под одним и тем же сегментом, но они не пересекаются, произойдет сбой. Например, добавив следующее в deps
:
datetime("2020-12-15T08:00:00.026Z"), "r1", 1, // D6
что не должно ничего добавлять к вычислению, может привести к неправильному поведению. Это связано с тем, что d4
это предыдущий пункт, и он не имеет точки соприкосновения d6
, хотя d3
охватывает их оба.
Чтобы решить эту проблему, вам нужно повторить ту же логику шагов 3-5. К сожалению, в Kusto нет рекурсий, поэтому вы не можете решить эту проблему для любого вида ввода. Но если предположить, что на самом деле нет таких глубоких случаев, которые нарушают эту логику, я думаю, что это достаточно хорошо.
Комментарии:
1. Потрясающе! Большое спасибо за этот отличный ответ и очень четкое объяснение! <3
2. Конечно @nulltoken 🙂 Раньше я работал разработчиком в Kusto. Это отличный проект. Большое спасибо за вознаграждение!!
Ответ №2:
Взгляните на приведенный ниже запрос, чтобы увидеть, может ли он соответствовать вашим требованиям:
let reqs = datatable (timestamp: datetime, id:string, duration: real, key1:string)
[
datetime("2020-12-15T08:00:00.000Z"), "r1", 31 , "k1" // R
];
let deps = datatable (timestamp: datetime, operation_ParentId:string, duration: real,name:string)
[
datetime("2020-12-15T08:00:00.002Z"), "r1", 7, "D1",
datetime("2020-12-15T08:00:00.007Z"), "r1", 8, "D2",
datetime("2020-12-15T08:00:00.021Z"), "r1", 6, "D3",
datetime("2020-12-15T08:00:00.023Z"), "r1", 2, "D4",
datetime("2020-12-15T08:00:00.006Z"), "r1", 4, "D5"
];
let d2 = deps
| where name !in ("D4","D5")
| summarize a=sum(duration)-2
| extend key1="k1";
reqs
| join d2 on key1
| extend result = duration - a
| project result
Результат теста:
Комментарии:
1. Спасибо за это. Однако вопрос был о том, как «измерить «собственную» продолжительность запросов (вычитая длительности зависимостей)» в целом, а не о том, как решить этот конкретный пример. Обновление вопроса, чтобы сделать намерение более ясным.