Timescale Cloud:性能、规模、企业版

自托管产品

MST

本节包含一些用于排查连续聚合常见问题的思路。

连续聚合使用水印来指示哪些时间桶已物化。当您查询连续聚合时,您的查询将返回水印之前的物化数据。它返回水印之后的实时、未物化数据。

在某些情况下,水印可能位于未来。如果发生这种情况,所有桶,包括最新的桶,都会被物化并低于水印。不返回实时数据。

如果您在时间窗口 `<START_TIME>, NULL` 上刷新连续聚合,这会物化所有最新数据,则可能会发生这种情况。如果您使用 `WITH DATA` 选项创建连续聚合,也可能会发生这种情况。这也会隐式地以 `NULL, NULL` 的窗口刷新您的连续聚合。

要解决此问题,请使用 `WITH NO DATA` 选项创建新的连续聚合。然后使用策略在显式时间窗口上刷新此连续聚合。

  1. 使用 `WITH NO DATA` 选项创建连续聚合

    CREATE MATERIALIZED VIEW <continuous_aggregate_name>
    WITH (timescaledb.continuous)
    AS SELECT time_bucket('<interval>', <partition_column>),
    <other_columns_to_select>,
    ...
    FROM <hypertable>
    GROUP BY bucket, <optional_other_columns>
    WITH NO DATA;
  2. 使用带有显式 `end_offset` 的策略刷新连续聚合。例如:

    SELECT add_continuous_aggregate_policy('<continuous_aggregate_name>',
    start_offset => INTERVAL '30 day',
    end_offset => INTERVAL '1 hour',
    schedule_interval => INTERVAL '1 hour');
  3. 检查您的新连续聚合的水印,确保它在过去而非未来。

    获取包含实际连续聚合数据的物化超表的 ID

    SELECT id FROM _timescaledb_catalog.hypertable
    WHERE table_name=(
    SELECT materialization_hypertable_name
    FROM timescaledb_information.continuous_aggregates
    WHERE view_name='<continuous_aggregate_name>'
    );
  4. 使用返回的 ID 查询水印的时间戳

    对于 TimescaleDB >= 2.12

    SELECT COALESCE(
    _timescaledb_functions.to_timestamp(_timescaledb_functions.cagg_watermark(<ID>)),
    '-infinity'::timestamp with time zone
    );

    对于 TimescaleDB < 2.12

    SELECT COALESCE(
    _timescaledb_internal.to_timestamp(_timescaledb_internal.cagg_watermark(<ID>)),
    '-infinity'::timestamp with time zone
    );
警告

如果您选择在创建新连续聚合后删除旧的连续聚合,请注意历史数据丢失。如果您的旧连续聚合包含您从原始超表中删除的数据(例如通过数据保留策略),则这些删除的数据将不会包含在您的新连续聚合中。

ERROR: cannot create continuous aggregate with incompatible bucket width
DETAIL: Time bucket width of "<BUCKET>" [1 year] should be multiple of the time bucket width of "<BUCKET>" [1 day].

如果您尝试创建分层连续聚合,则必须使用兼容的时间桶。您不能在具有可变宽度时间桶的连续聚合之上创建具有固定宽度时间桶的连续聚合。有关更多信息,请参阅分层连续聚合中的限制部分。

在超表上设置的保留策略不适用于从该超表创建的任何连续聚合。这允许您为原始数据和汇总数据设置不同的保留期。要将保留策略应用于连续聚合,请在连续聚合本身上设置策略。

物化视图通常与有序数据一起使用。如果您插入历史数据或与当前时间无关的数据,您需要刷新策略并重新评估从过去拖到现在的值。

您可以为超表设置一个插入后规则或执行 upsert,以触发某些操作来验证数据合并时需要刷新的内容。

假设您插入了名为 A、B、D 和 F 的有序时间帧,并且您已经有一个连续聚合正在查找此数据。如果您现在插入 E,则需要刷新 E 和 F。但是,如果您插入 C,则需要刷新 C、D、E 和 F。

例如:

  1. A、B、D 和 F 已在视图中物化了所有数据。
  2. 要插入 C,请将数据拆分为 `AB` 和 `DEF` 子集。
  3. `AB` 是一致的,物化数据也是一致的;您只需要重用它。
  4. 插入 C、`DEF`,并在 C 之后刷新策略。

这可能会消耗大量资源进行处理,特别是如果您过去有任何重要数据也需要带到现在。

考虑一个示例,您在一个超表上有 300 列,并使用其中五列进行连续聚合。在这种情况下,刷新可能会很困难,将这些列隔离到另一个超表中会更有意义。或者,您可以为每个指标创建一个超表并独立刷新它们。

当您使用 `cagg_migrate` 将连续聚合从旧格式迁移到新格式时,可能会遇到权限错误。执行迁移的用户必须具有以下权限:

  • 对表 `_timescale_catalog.continuous_agg_migrate_plan` 和 `_timescale_catalog.continuous_agg_migrate_plan_step` 具有 SELECT、INSERT 和 UPDATE 权限
  • 对序列 `_timescaledb_catalog.continuous_agg_migrate_plan_step_step_id_seq` 具有 USAGE 权限

要解决此问题,请切换到能够授予权限的用户,并向执行迁移的用户授予以下权限:

GRANT SELECT, INSERT, UPDATE ON TABLE _timescaledb_catalog.continuous_agg_migrate_plan TO <USER>;
GRANT SELECT, INSERT, UPDATE ON TABLE _timescaledb_catalog.continuous_agg_migrate_plan_step TO <USER>;
GRANT USAGE ON SEQUENCE _timescaledb_catalog.continuous_agg_migrate_plan_step_step_id_seq TO <USER>;

连续聚合并非适用于所有查询。例如,TimescaleDB 不支持对连续聚合使用窗口函数。如果您使用不受支持的函数,您会看到以下错误:

ERROR: invalid continuous aggregate view
SQL state: 0A000

下表总结了连续聚合中支持的聚合函数:

函数、子句或特性TimescaleDB 2.6 及更早版本TimescaleDB 2.7、2.8 和 2.9TimescaleDB 2.10 及更高版本
可并行聚合函数
不可并行 SQL 聚合函数
ORDER BY
有序集合聚合
假设集合聚合
聚合函数中的 `DISTINCT`
聚合函数中的 `FILTER`
`FROM` 子句支持 `JOINS`

`DISTINCT` 在聚合函数中有效,但在查询定义中无效。例如,对于表:

CREATE TABLE public.candle(
symbol_id uuid NOT NULL,
symbol text NOT NULL,
"time" timestamp with time zone NOT NULL,
open double precision NOT NULL,
high double precision NOT NULL,
low double precision NOT NULL,
close double precision NOT NULL,
volume double precision NOT NULL
);
  • 以下代码有效:
    CREATE MATERIALIZED VIEW candles_start_end
    WITH (timescaledb.continuous) AS
    SELECT time_bucket('1 hour', "time"), COUNT(DISTINCT symbol), first(time, time) as first_candle, last(time, time) as last_candle
    FROM candle
    GROUP BY 1;
  • 以下代码无效:
    CREATE MATERIALIZED VIEW candles_start_end
    WITH (timescaledb.continuous) AS
    SELECT DISTINCT ON (symbol)
    symbol,symbol_id, first(time, time) as first_candle, last(time, time) as last_candle
    FROM candle
    GROUP BY symbol_id;

当您查询连续聚合时,实时聚合会自动添加最新数据。换句话说,它们包含比您上次物化桶*更近期*的数据。

如果您向已物化的桶添加新的*历史*数据,它将不会反映在实时聚合中。您应该等待下一次计划刷新,或者通过调用 `refresh_continuous_aggregate` 手动刷新。您可以将实时聚合视为历史数据最终一致。

以下示例演示了其工作原理:

  1. 创建超表

    CREATE TABLE conditions(
    day DATE NOT NULL,
    city text NOT NULL,
    temperature INT NOT NULL
    )
    WITH (
    tsdb.hypertable,
    tsdb.partition_column='day',
    tsdb.chunk_interval='1 day'
    );

    如果您自托管 TimescaleDB v2.19.3 及更早版本,请创建一个PostgreSQL 关系表,然后使用 create_hypertable 进行转换。然后通过调用 ALTER TABLE 启用 hypercore。

  2. 向超表添加数据

    INSERT INTO conditions (day, city, temperature) VALUES
    ('2021-06-14', 'Moscow', 26),
    ('2021-06-15', 'Moscow', 22),
    ('2021-06-16', 'Moscow', 24),
    ('2021-06-17', 'Moscow', 24),
    ('2021-06-18', 'Moscow', 27),
    ('2021-06-19', 'Moscow', 28),
    ('2021-06-20', 'Moscow', 30),
    ('2021-06-21', 'Moscow', 31),
    ('2021-06-22', 'Moscow', 34),
    ('2021-06-23', 'Moscow', 34),
    ('2021-06-24', 'Moscow', 34),
    ('2021-06-25', 'Moscow', 32),
    ('2021-06-26', 'Moscow', 32),
    ('2021-06-27', 'Moscow', 31);
  3. 创建连续聚合但不物化任何数据

    1. 创建连续聚合

      CREATE MATERIALIZED VIEW conditions_summary
      WITH (timescaledb.continuous) AS
      SELECT city,
      time_bucket('7 days', day) AS bucket,
      MIN(temperature),
      MAX(temperature)
      FROM conditions
      GROUP BY city, bucket
      WITH NO DATA;
    2. 检查您的数据

      SELECT * FROM conditions_summary ORDER BY bucket;

      连续聚合上的查询直接从超表获取数据

      城市最小值最大值
      莫斯科2021-06-142230
      莫斯科2021-06-213134
  4. 将数据物化到连续聚合中

    1. 添加刷新策略

      CALL refresh_continuous_aggregate('conditions_summary', '2021-06-14', '2021-06-21');
    2. 检查您的数据

      SELECT * FROM conditions_summary ORDER BY bucket;

      选择查询返回相同的数据,如预期,但这次数据是从底层的物化表获取的。

      城市最小值最大值
      莫斯科2021-06-142230
      莫斯科2021-06-213134
  1. 更新先前物化的桶中的数据

    1. 更新超表中的数据

      UPDATE conditions
      SET temperature = 35
      WHERE day = '2021-06-14' and city = 'Moscow';
    2. 检查您的数据

      SELECT * FROM conditions_summary ORDER BY bucket;

      当您查询连续聚合时,更新后的数据尚未可见。这是因为这些更改尚未物化。(同样,任何 INSERT 或 DELETE 也将不可见)。

      城市最小值最大值
      莫斯科2021-06-142230
      莫斯科2021-06-213134
  1. 再次刷新数据以更新先前物化的区域

    1. 刷新数据
      CALL refresh_continuous_aggregate('conditions_summary', '2021-06-14', '2021-06-21');
  2. 检查您的数据

    SELECT * FROM conditions_summary ORDER BY bucket;

    您会看到类似以下内容:

    城市最小值最大值
    莫斯科2021-06-142235
    莫斯科2021-06-213134

您的计划任务可能因各种原因停止运行。在自托管 TimescaleDB 上,您可以通过重新启动后台工作程序来解决此问题:

在 Timescale 和 Managed Service for TimescaleDB 上,通过执行以下任一操作来重新启动后台工作程序:

  • 运行 `SELECT timescaledb_pre_restore()`,然后运行 `SELECT timescaledb_post_restore()`。
  • 关闭并重新打开服务。这可能会导致几分钟的停机时间,因为服务会从备份中恢复并重播预写日志。

当您的查询使用“上次观测值前向填充 (locf)”函数时,默认情况下查询会前向填充 NULL 值。如果您希望函数忽略 NULL 值,您可以在查询中将 `treat_null_as_missing=TRUE` 设置为第二个参数。例如:

dev=# select * FROM (select time_bucket_gapfill(4, time,-5,13), locf(avg(v)::int,treat_null_as_missing:=true) FROM (VALUES (0,0),(8,NULL)) v(time, v) WHERE time BETWEEN 0 AND 10 GROUP BY 1) i ORDER BY 1 DESC;
time_bucket_gapfill | locf
---------------------+------
12 | 0
8 | 0
4 | 0
0 | 0
-4 |
-8 |
(6 rows)

关键词

在此页面上发现问题?报告问题 或 在 GitHub 上编辑此页面