增量刷新函数支持记录

更新时间:
复制 MD 格式

本文记录 Dynamic Table 增量刷新支持的函数,包括函数支持一览表及 row_number/rank、lead/lag、hg_id_encoding、min_by/max_by 等函数的使用说明与示例。

函数支持一览表

Dynamic Table 增量刷新支持基本的聚合函数:COUNT、SUM、MIN/MAX、COUNT DISTINCT,更多复杂函数的支持记录如下表所示。

函数名

函数说明

dynamic table使用示例

支持的版本

row_number / rank

窗口函数,用于实现TopN数据加工。支持在增量模式下使用row_number()或rank()函数对数据进行分组排序并筛选前N条记录。

参见Dynamic Table 使用示例

  • 仅 Hologres V4.2 及以上版本支持

lead / lag

窗口函数,用于取分组内排序后的后一行或前一行的值,常用于计算相邻记录的差值、环比、状态变化等场景。使用时须同时指定 PARTITION BY 和 ORDER BY。

参见Dynamic Table 使用示例

  • 仅 Hologres V5.0 及以上版本支持

  • 仅支持单参数形式 lead(expr)lag(expr),不支持 offset 和 default 参数

hg_id_encoding_int32 / hg_id_encoding_int64

txet类型的UID字段映射成int/bigint类型,每次调用函数时,会自动映射数据写入与更新user mapping表,通常使用在计算长UV场景中,用户UIDtext字段,映射成int类型,方便进行rb计算。

参见Hologres Dynamic Table任意长周期UV计算方案

  • 仅 Hologres V4.1 及以上版本支持该函数

min_by / max_by

min/max_by用于比较expr2列的最大/最小值,给出对应的expr1列的值

min/max_by(expr1, expr2)
  • 参数说明:expr2用于比较大小的列,expr1展示的对应列

  • 返回值说明:expr2最大/最小行对应的expr1的值

参见Dynamic Table 使用示例

  • 仅 Hologres V4.0 及以上版本支持

RB_BUILD_AGG


RB_BUILD_AGG(<column>)

说明:column的参数类型支持int32int64,详细使用见文档RoaringBitmap函数

参见Hologres Dynamic Table任意长周期UV计算方案

  • Hologres V3.1 及以上版本

string_agg

string_agg([distinct] column_expr, const_expr)

说明:

  • 参数类型:column_expr需为text/char/varchar类型,const_expr需为text类型的常量

  • 不支持使用order by语法

  • 从 Hologres V3.1.10 版本开始支持string_agg([distinct]

CREATE DYNAMIC TABLE string_agg_test_dt  
  WITH (
    freshness = '3 minutes', 
    refresh_mode = 'incremental') 
  as 
  SELECT day,
         string_agg(gameversion, ',') AS gameversion_list
    FROM base_table group by day;
  • Hologres V3.1 及以上版本

  • 从 Hologres V3.1.10 版本开始支持string_agg([distinct]

array_agg

array_agg([distinct] expr)

说明:

  • expr参数类型:支持bool类型、所有数字类型、text类型、bytea类型

  • 不支持使用order by语法

  • 从 Hologres V3.1.10 版本开始支持string_agg([distinct]

CREATE DYNAMIC TABLE array_agg_test_dt  
  WITH (
    freshness = '3 minutes', 
    refresh_mode = 'incremental') 
  as 
  SELECT day,
         array_agg(gameversion) AS gameversion_list
    FROM base_table group by day;
  • Hologres V3.1 及以上版本

  • 从 Hologres V3.1.10 版本开始支持string_agg([distinct]

any_value

在包含group by的聚合查询中,从每个聚合分组中随机选择某行的结果返回,结果不确定

CREATE  DYNAMIC TABLE dt_t0
WITH (
  -- dynamic table的属性
  freshness = '1 minutes', 
  auto_refresh_mode = 'auto'
)
AS 
select a,any_value(c),sum(b) from t0 group by a;
  • Hologres V3.1.5 及以上版本支持

  • any_value的输入参数仅支持intbinary类型

row_number / rank

从 Hologres V4.2 版本开始支持 row_number() 和 rank() 窗口函数,能够在 Dynamic Table 增量模式下实现 TopN 数据加工。支持通过 PARTITION BY 进行分组,ORDER BY 进行排序,并在外层筛选前 N 条记录。

语法

SELECT [column_list]
FROM (
   SELECT [column_list],
     ROW_NUMBER() OVER ([PARTITION BY col1[, col2...]]
       ORDER BY col1 [asc|desc][, col2 [asc|desc]...]) AS rownum
   FROM table_name)
WHERE rownum <= N [AND conditions]

参数说明:

  • PARTITION BY col1[, col2...]:可选,指定分组列。

  • ORDER BY col1 [asc|desc][, col2 [asc|desc]...]:必选,指定排序列及排序方向。

  • rownum <= N:必选,筛选前 N 条记录。

使用限制

  • 仅 Hologres V4.2 及以上版本支持。

  • 若刷新模式指定为 auto,会自动推导为 incremental 模式。

Dynamic Table 使用示例

CREATE TABLE orders (
  order_id bigint,
  product_id bigint,
  amount bigint
);

INSERT INTO orders
SELECT i, i % 100, (random() * 1000000)::bigint
FROM generate_series(1, 10000)i;

CREATE DYNAMIC TABLE top3_orders
WITH (
  freshness = '5 minutes',
  auto_refresh_mode = 'incremental'
) AS
SELECT order_id, product_id, amount
FROM (
   SELECT order_id, product_id, amount,
     ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY amount desc) AS rownum
   FROM orders)
WHERE rownum <= 3;

SELECT * FROM top3_orders WHERE product_id = 1;

lead / lag

从 Hologres V5.0 版本开始支持 lead() 和 lag() 窗口函数,能够在 Dynamic Table 增量模式下取分组内排序后的后一行或前一行的值,常用于计算相邻记录的差值、环比、状态变化等场景。

语法

SELECT [column_list],
  {lead | lag}(<expr>) OVER (
    PARTITION BY col1[, col2...]
    ORDER BY col1 [asc|desc] [nulls first|nulls last][, col2 ...]) AS <alias>
FROM table_name;

参数

  • expr:取值列。该列必须同时出现在 SELECT 列表中,否则刷新时报错,详情请参见下方使用限制

  • PARTITION BY:必选,用于分组的列,支持多列。

  • ORDER BY:必选,用于排序的列,支持多列排序、asc/desc、NULLS FIRST/NULLS LAST。

使用限制

  • 仅 Hologres V5.0 及以上版本支持。

  • PARTITION BY 和 ORDER BY 均为必选。

  • 仅支持单参数形式 lead(expr)lag(expr),即偏移量固定为 1,不支持 lead(expr, offset)lead(expr, offset, default)

  • lead 和 lag 的入参列必须出现在 SELECT 列表中。例如 SELECT id, k, lead(price) OVER (...) 会在刷新时失败,需改写为 SELECT id, k, price, lead(price) OVER (...)

  • PARTITION BY 与 ORDER BY 的列不支持浮点类型(float、float4、float8、real、double precision)。如需按小数排序,请使用 numeric 或 decimal 类型。可用作分组或排序键的类型包括:int、bigint、smallint、numeric/decimal、text/varchar、date、timestamp、timestamptz、bool。

  • 建议 ORDER BY 列在每个分组内取值唯一。当同一分组内存在多行排序键相同(含多个 NULL)时,增量刷新使用内部行序号打破并列,与全量刷新、普通 OLAP 查询的并列处理依据不同,结果可能不一致。两者在 SQL 语义上均为合法解,如需结果确定,请在 ORDER BY 中追加唯一列作为并列裁决列。

  • 不支持 IGNORE NULLS 和 RESPECT NULLS 语法。

  • 首次刷新需要构建全量 state,耗时可能较长。

  • 增量刷新的耗时主要由本次变更触碰到的分组占比决定,而非变更行数。变更集中在少量分组时增量优势明显;如果每次变更铺满全部分组,建议使用全量刷新。此外,增量刷新会额外维护 state 表,存储开销显著高于全量刷新,请纳入容量评估。

Dynamic Table 使用示例

以下示例计算每个用户相邻两次行为的金额变化。

-- 创建源表:用户行为明细
CREATE TABLE user_events (
  event_id bigint,
  user_id  text,
  event_ts timestamptz,
  amount   numeric(10,2)
);

INSERT INTO user_events VALUES
  (1, 'u1', '2026-08-20 10:00:00+08', 100.00),
  (2, 'u1', '2026-08-20 11:00:00+08', 150.00),
  (3, 'u1', '2026-08-20 12:00:00+08', 120.00),
  (4, 'u2', '2026-08-20 09:00:00+08', 80.00),
  (5, 'u2', '2026-08-20 10:30:00+08', 95.00);

-- 创建Dynamic Table,注意入参列amount必须出现在SELECT列表中
CREATE DYNAMIC TABLE user_amount_diff
WITH (
  freshness = '5 minutes',
  auto_refresh_mode = 'incremental'
) AS
SELECT
  event_id,
  user_id,
  event_ts,
  amount,
  lag(amount) OVER (PARTITION BY user_id ORDER BY event_ts) AS prev_amount,
  amount - COALESCE(lag(amount) OVER (PARTITION BY user_id ORDER BY event_ts), 0) AS diff
FROM user_events;

SELECT * FROM user_amount_diff ORDER BY user_id, event_ts;

查询结果如下。

 event_id | user_id |        event_ts        | amount | prev_amount |  diff
----------+---------+------------------------+--------+-------------+--------
        1 | u1      | 2026-08-20 10:00:00+08 | 100.00 |             | 100.00
        2 | u1      | 2026-08-20 11:00:00+08 | 150.00 |      100.00 |  50.00
        3 | u1      | 2026-08-20 12:00:00+08 | 120.00 |      150.00 | -30.00
        4 | u2      | 2026-08-20 09:00:00+08 |  80.00 |             |  80.00
        5 | u2      | 2026-08-20 10:30:00+08 |  95.00 |       80.00 |  15.00
(5 rows)

hg_id_encoding_int32 / hg_id_encoding_int64

从 Hologres V4.1 版本开始支持 hg_id_encoding_int32 / hg_id_encoding_int64,可将 text 类型的 uid 字段映射成 int32/int64,自动将数据写入 user_mapping 表,与 Dynamic Table 增量刷新及 RoaringBitmap 结合可实现长周期 UV 计算。详情可参考用户行为分析最佳实践文档。

语法

hg_id_encoding_int4(<user_id>, '<mapping_tablename>')
hg_id_encoding_int8(<user_id>, '<mapping_tablename>')

参数说明:

  • 第一个参数:text 类型的 uid 列。

  • 第二个参数:user_mapping 的表名,需提前创建 user mapping 表,将 text 类型的 uid 映射成 int 类型。

使用限制

  • user_mapping 必须有主键,且主键之外只有一个 Serial 字段;目前仅支持主键为 text 类型且为单列主键。

  • 第一个参数仅支持 text 类型的 uid 字段,不支持 NULL 值,否则函数执行报错。

  • 调用函数时会自动将 mapping 数据写入 user_mapping 表;若 uid 已存在则忽略,新数据则新增。

  • 仅 Hologres V4.1 及以上版本支持。

使用示例

CREATE TABLE base_table(user_id text);
INSERT INTO base_table VALUES('a');

-- 创建 user_mapping 表
CREATE TABLE uid_mapping(user_id text PRIMARY KEY, id serial);

-- 将 base 表的 uid 经 hg_id_encoding_int4 映射后自动写入 mapping 表
SELECT user_id, hg_id_encoding_int4(user_id, 'uid_mapping') AS res FROM base_table;

-- 查询 mapping 表
-- user_id | id
-- --------+----
--   a     |  1

min_by / max_by

min_by / max_by 用于按 expr2 列取最小/最大值,返回对应的 expr1 列的值。

min_by(expr1, expr2)
max_by(expr1, expr2)

参数说明:expr2 为用于比较大小的列,expr1 为要展示的对应列。返回值:expr2 最小/最大行对应的 expr1 的值。使用限制:仅 Hologres V4.0 及以上版本支持。

Dynamic Table 使用示例

DROP TABLE IF EXISTS detail;
CREATE TABLE detail (
  userid       text,
  event_id     text,
  create_time  timestamptz
);

INSERT INTO detail(userid, event_id, create_time) VALUES
  ('user_1', 'e1', '2024-12-20 10:00:00+08'),
  ('user_1', 'e2', '2024-12-20 11:30:00+08'),
  ('user_1', 'e3', '2024-12-21 09:15:00+08'),
  ('user_2', 'e4', '2024-12-20 08:05:00+08'),
  ('user_2', 'e5', '2024-12-22 14:20:00+08'),
  ('user_3', 'e6', '2024-12-21 16:45:00+08');

DROP TABLE IF EXISTS detail_user_first_last_event;

CREATE DYNAMIC TABLE detail_user_first_last_event
WITH (
  auto_refresh_mode = 'incremental',
  computing_resource = 'local',
  freshness = '3 minutes'
)
AS
SELECT
  userid,
  min_by(event_id, create_time) AS first_event_id,
  max_by(event_id, create_time) AS last_event_id,
  date_trunc('day', max(create_time))::date AS dt
FROM detail
GROUP BY userid;