Подзапрос в ClickHouse без оптимизации где - PullRequest
0 голосов
/ 14 февраля 2020

У меня есть упрощенная таблица в ClickHouse, в которой хранятся события изменения статуса триггера

CREATE TABLE trigger_events_test (
 `CreatedAt` DateTime,
 `Id` UUID,
 `TriggerId` Int,
 `Status` Enum8('Ok' = 1,
 'Problem1' = 2,
 'Problem2' = 3,
 'Problem3' = 4,
 'Problem4' = 5,
 'Disabled' = 6)
) ENGINE = MergeTree() PARTITION BY (toYYYYMM(CreatedAt)) ORDER BY (CreatedAt, TriggerId) SETTINGS index_granularity = 8192;

Допустим, таблица содержит 5 записей:

INSERT into trigger_events_test(CreatedAt, Id, TriggerId, Status)
values
('2020-02-14 10:16:00', '9be6f472-aa15-418f-ac6d-e8ceb8dc462e', 1, 'Problem1'),
('2020-02-14 10:17:00', '260bbf0c-fbbc-44b4-835f-dfb3cdad11f1', 1, 'Ok'),
('2020-02-14 10:18:00', 'cb35f07e-a539-4932-8f26-d95df8de6686', 1, 'Problem2'),
('2020-02-14 10:19:00', '7c5a78d7-8b41-4353-89c2-232edcbb2457', 1, 'Problem3'),
('2020-02-14 10:20:00', '260bbf0c-fbbc-44b4-835f-dfb3cdad11f1', 1, 'Ok'),

Я хочу выбрать историю изменения статуса триггера (id = 1) с продолжительностью статуса на основе предыдущего статуса. Поэтому я могу сделать запрос

SELECT 
   Id,
   TriggerId,
   Status,
   CreatedAt,
   if(neighbor(TriggerId,1) = TriggerId, neighbor(CreatedAt,1,now()), now()) AS DateEnd,
   ABS(CreatedAt - DateEnd) AS Duration
FROM trigger_events_test 
   ORDER BY TriggerId ASC, CreatedAt ASC

, который дает правильный ответ

Id                                  |TriggerId|Status  |CreatedAt          |DateEnd            |Duration|
------------------------------------|---------|--------|-------------------|-------------------|--------|
9be6f472-aa15-418f-ac6d-e8ceb8dc462e|        1|Problem1|2020-02-14 10:16:00|2020-02-14 10:17:00|      60|
260bbf0c-fbbc-44b4-835f-dfb3cdad11f1|        1|Ok      |2020-02-14 10:17:00|2020-02-14 10:18:00|      60|
cb35f07e-a539-4932-8f26-d95df8de6686|        1|Problem2|2020-02-14 10:18:00|2020-02-14 10:19:00|      60|
7c5a78d7-8b41-4353-89c2-232edcbb2457|        1|Problem3|2020-02-14 10:19:00|2020-02-14 10:20:00|      60|
260bbf0c-fbbc-44b4-835f-dfb3cdad11f1|        1|Ok      |2020-02-14 10:20:00|2020-02-14 10:54:15|    2055|

Но на самом деле я хочу фильтровать записи по дате с обоих концов и по статусам. Я сделал подзапрос, который возвращает не то, что я ожидал.

SELECT *
FROM (SELECT 
       Id,
       TriggerId,
       Status,
       CreatedAt,
       if(neighbor(TriggerId,1) = TriggerId, neighbor(CreatedAt,1,now()), now()) AS DateEnd,
       ABS(CreatedAt - DateEnd) AS Duration
   FROM trigger_events_test 
       ORDER BY TriggerId ASC, CreatedAt ASC)
WHERE Status IN ('Problem1', 'Problem2', 'Problem3', 'Problem4') AND (DateEnd >= '2020-02-14 10:17:00' AND CreatedAt <= now())

Результат:

Id                                  |TriggerId|Status  |CreatedAt          |DateEnd            |Duration|
------------------------------------|---------|--------|-------------------|-------------------|--------|
9be6f472-aa15-418f-ac6d-e8ceb8dc462e|        1|Problem1|2020-02-14 10:16:00|2020-02-14 10:18:00|     120|
cb35f07e-a539-4932-8f26-d95df8de6686|        1|Problem2|2020-02-14 10:18:00|2020-02-14 10:19:00|      60|
7c5a78d7-8b41-4353-89c2-232edcbb2457|        1|Problem3|2020-02-14 10:19:00|2020-02-14 10:58:03|    2343|

Как вы можете видеть, "Проблема 1" теперь возвращает 120 сек c длительности, и Проблема 3 думает, что имеет еще не закончено. Я полагаю, что ClickHouse оптимизирует запрос и выполняет условие условия в подзапросе.

Может кто-нибудь помочь мне выяснить, как сделать правильный запрос?

...