Материализованный вид для вычисленных результатов

#clickhouse

#clickhouse

Вопрос:

У меня есть таблица, подобная приведенной ниже, где состояние — это ограниченный набор обновлений (например, Start, End).:

 CREATE TABLE event_updates (
  event_id Int32,
  timestamp DateTime,
  state String
) ENGINE Log;
  

И я хочу иметь возможность быстро запускать запросы, такие как:

 SELECT count(*)
FROM (
 SELECT event_id,
  minOrNullIf(timestamp, state = 'Start') as start,
  minOrNullIf(timestamp, state = 'End') as end,
  end - start as duration,
  duration < 10 as is_fast,
  duration > 300 as is_slow
 FROM event_updates
 GROUP BY event_id)
WHERE start >= '2020-08-20 00:00:00'
AND start < '2020-08-20 00:00:00'
AND is_slow;
  

Но эти запросы выполняются медленно, когда данных много, я предполагаю, потому что вычисления требуются для каждой строки.

Примерные данные:

 ┌─event_id─┬───────────timestamp─┬─state─┐
│        12020-08-21 09:58:00Start │
│        12020-08-21 10:18:00End   │
│        22020-08-21 10:23:00Start │
│        22020-08-21 10:23:05End   │
│        32020-08-21 10:23:00Start │
│        32020-08-21 10:24:00End   │
│        32020-08-21 11:24:00End   │
│        42020-08-21 10:30:00Start │
└──────────┴─────────────────────┴───────┘
  

И пример запроса:

 SELECT
    event_id,
    minOrNullIf(timestamp, state = 'Start') AS start,
    minOrNullIf(timestamp, state = 'End') AS end,
    end - start AS duration,
    duration < 10 AS is_fast,
    duration > 300 AS is_slow
FROM event_updates
GROUP BY event_id
ORDER BY event_id ASC

┌─event_id─┬───────────────start─┬─────────────────end─┬─duration─┬─is_fast─┬─is_slow─┐
│        12020-08-21 09:58:002020-08-21 10:18:00120001 │
│        22020-08-21 10:23:002020-08-21 10:23:05510 │
│        32020-08-21 10:23:002020-08-21 10:24:006000 │
│        42020-08-21 10:30:00 │                ᴺᵁᴸᴸ │     ᴺᵁᴸᴸ │    ᴺᵁᴸᴸ │    ᴺᵁᴸᴸ │
└──────────┴─────────────────────┴─────────────────────┴──────────┴─────────┴─────────┘
  

То, что я хотел бы создать, — это предварительно рассчитанная таблица, подобная:

 CREATE TABLE event_stats (
  event_id Int32,
  start Nullable(DateTime),
  end Nullable(DateTime),
  duration Nullable(Int32),
  is_fast Nullable(UInt8),
  is_slow Nullable(UInt8)
);
  

Но я не могу понять, как создать эту таблицу с материализованным видом или найти лучший способ.

Ответ №1:

Сначала я бы

  1. используйте MergeTree-engine вместо журнала, чтобы получить преимущества от сортировки по ключу
 CREATE TABLE event_updates (
  event_id Int32,
  timestamp DateTime,
  state String
) ENGINE MergeTree
PARTITION BY toYYYYMM(timestamp)
ORDER BY (timestamp, state);
  
  1. ограничьте исходный набор данных, применив WHERE-предложение к отметке времени и состоянию (в вашем запросе обрабатывается весь набор данных)
 SELECT count(*)
FROM (
 SELECT event_id,
  minOrNullIf(timestamp, state = 'Start') as start,
  minOrNullIf(timestamp, state = 'End') as end,
  end - start as duration,
  duration < 10 as is_fast,
  duration > 300 as is_slow
 FROM event_updates
 WHERE timestamp >= '2020-08-20 00:00:00' AND timestamp < '2020-09-20 00:00:00' 
    AND state IN ('Start', 'End')
 GROUP BY event_id
 HAVING start >= '2020-08-20 00:00:00' AND start < '2020-09-20 00:00:00' 
   AND is_slow);
  

Если эти методы не помогают, необходимо рассмотреть возможность использования AggregatingMergeTree для обработки предварительно вычисленных агрегатов, а не необработанных данных.