Агрегация в реальном времени не обновлена

#timescaledb #real-time-data #continuous-aggregates

Вопрос:

Я испытываю агрегацию в реальном времени, чтобы не быть в курсе событий в реальном времени. Есть ли что-то, чего мне не хватает?

Воспроизводимый пример в версии 2.4.2 с использованием текущего образа docker timescale/timescaledb:latest-pg12 :

 CREATE TABLE data
(
    time  TIMESTAMPTZ      NOT NULL,
    value DOUBLE PRECISION NOT NULL
);

SELECT create_hypertable('data', 'time', chunk_time_interval => interval '1d');

INSERT INTO data (time, value)
VALUES ('2020-01-01', 100);

CREATE MATERIALIZED VIEW data_daily WITH (timescaledb.continuous)
AS
SELECT time_bucket('1 day', time) AS time,
       avg(value)                 AS avg,
       count(*)                   AS count
FROM data
GROUP BY 1;
ALTER MATERIALIZED VIEW data_daily SET (timescaledb.materialized_only = false);
 

Теперь, когда я бегу SELECT * FROM data_daily , я получаю ожидаемый результат:

 time, avg, count
2020-01-01 00:00:00.000000, 100, 1
 

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

 INSERT INTO data (time, value) VALUES ('2020-01-01', 150);

SELECT * FROM data_daily;
 

Выход:

 time, avg, count
2020-01-01 00:00:00.000000, 100, 1
 

Обновление вручную, а затем повторный запрос покажет ожидаемый результат.

 CALL refresh_continuous_aggregate('data_daily', '1900-01-01', '2100-01-01');

SELECT * FROM data_daily;
 

Выход:

 time, avg, count
2020-01-01 00:00:00.000000, 125, 2
 

Есть ли что-нибудь еще, что необходимо настроить для работы агрегации в реальном времени?
Из документации я понимаю, что настройки materialized_only = false должно быть достаточно (и даже не обязательно, так как это значение по умолчанию).

Для справки, это план запроса после второй вставки и перед обновлением вручную:

  Append  (cost=0.15..59.98 rows=400 width=24) (actual time=0.138..0.200 rows=1 loops=1)
   ->  GroupAggregate  (cost=0.15..21.76 rows=200 width=24) (actual time=0.130..0.151 rows=1 loops=1)
         Group Key: _materialized_hypertable_48."time"
         ->  Custom Scan (ChunkAppend) on _materialized_hypertable_48  (cost=0.15..16.81 rows=260 width=72) (actual time=0.021..0.046 rows=1 loops=1)
               Order: _materialized_hypertable_48."time"
               Chunks excluded during startup: 0
               ->  Index Scan Backward using _hyper_48_315_chunk__materialized_hypertable_48_time_idx on _hyper_48_315_chunk  (cost=0.15..16.81 rows=260 width=72) (actual time=0.014..0.023 rows=1 loops=1)
                     Index Cond: ("time" < COALESCE(_timescaledb_internal.to_timestamp(_timescaledb_internal.cagg_watermark(48)), '-infinity'::timestamp with time zone))
   ->  GroupAggregate  (cost=0.16..32.23 rows=200 width=24) (actual time=0.010..0.021 rows=0 loops=1)
         Group Key: (time_bucket('1 day'::interval, data."time"))
         ->  Custom Scan (ChunkAppend) on data  (cost=0.16..24.60 rows=617 width=16) (actual time=0.003..0.007 rows=0 loops=1)
               Order: time_bucket('1 day'::interval, data."time")
               Chunks excluded during startup: 1
 Planning Time: 4.978 ms
 Execution Time: 0.384 ms
 

Ответ №1:

Это хороший вопрос, он определенно немного сбивает с толку в том, как работают непрерывные агрегаты.

Представление в реальном времени работает только с областями представления, которые еще не были материализованы вообще, оно не работает с областями, которые были материализованы, но теперь признаны недействительными. Это делается по соображениям предсказуемости производительности и из-за того, как работают материализация и аннулирование. Обычно окно обновления вызывается на некоторое время меньше , чем now() , скажем now() - '1 hour'::interval , затем вставки происходят с 1 часа назад вперед, затем представление в реальном времени выполнит запрос непосредственно в базовой таблице в регионе now()-'1 hour' -> > now() и вернет результаты из материализованной части для региона до этого. Может быть много маленьких областей, которые признаны недействительными, поэтому они будут выбраны только при следующем выполнении задания материализации. Вы могли бы сказать, что это в конечном итоге согласованное представление ваших данных.

Теперь для вас я бы сказал, что главное-запустить процедуру обновления не так далеко в будущее, а скорее придерживаться прошлого, и тогда вы увидите, что представление в реальном времени работает больше так, как вы ожидаете.