MARS3 DIMS 维度列声明

DIMS 子句用于在创建 MARS3 表时声明维度列。维度列通常是时序数据中的逻辑标识轴,例如时间戳、设备 ID、业务标签等。通过显式声明维度列,可以在系统目录中持久化维度信息,便于后续查看、迁移和工具集成。

维度列本质上仍是表中的普通列,可以参与查询、分布键、排序键和分区键定义。DIMS 的作用是为这些列增加维度语义标记,不会自动创建索引,也不会替代 DISTRIBUTED BYORDER BYPARTITION BY 的设计。

功能说明

使用 DIMS 子句声明维度列后,可以获得以下能力:

  • 维度元数据持久化:维度列标记会存储在系统目录中。
  • 备份恢复兼容:使用 pg_dump / pg_restore 迁移表结构时,维度元数据可以被保留。
  • psql 展示增强:使用 \d+ 查看表结构时,会展示 Dimensions 信息,列出该表的维度列。
  • 统一建模语义:在时序、设备监控、IoT 等场景中,可以显式区分指标列和维度列,使表结构更易理解和维护。

语法

CREATE TABLE table_name (
    data_column_1 type1,
    data_column_2 type2,
    ...
)
USING MARS3
  [WITH (...)]
  DIMS (dim_column_1 type1 [, dim_column_2 type2, ...])
  DISTRIBUTED BY (dist_key)
  ORDER BY (sort_keys);

DIMS 接受一个由括号包围的列定义列表,写法与 CREATE TABLE 主列列表中的列定义类似。

DIMS (column_name data_type [, column_name data_type, ...])

DIMS 子句中只允许定义列名、数据类型以及列级约束。不支持 LIKE 子句,也不支持表级约束。

基本用法

以下示例创建一张 MARS3 表,并将 tag 声明为维度列:

CREATE TABLE metrics (
    ts timestamp,
    value float8
)
USING MARS3
  DIMS (tag text)
  DISTRIBUTED BY (tag)
  ORDER BY (ts);

创建完成后,metrics 表包含 tagtsvalue 三列,其中 tag 被标记为维度列。

注意!
维度列会进入表的实际列定义中。因此,在 DISTRIBUTED BYORDER BY、查询语句和写入语句中,都可以像普通列一样引用维度列。

声明多个维度列

可以在 DIMS 中声明多个维度列:

CREATE TABLE sensor_data (
    reading numeric
)
USING MARS3
  DIMS (device_id int, ts timestamp)
  DISTRIBUTED BY (device_id)
  ORDER BY (device_id, ts);

该示例中,device_idts 都被声明为维度列。它们同时也可以作为分布键和排序键使用。

维度列作为排序键

维度列可以在 ORDER BY 中引用,用于定义 MARS3 表的排序键:

CREATE TABLE logs (
    level int,
    msg text
)
USING MARS3
  DIMS (ts timestamp)
  DISTRIBUTED BY (level)
  ORDER BY (ts);

该示例中,ts 是维度列,同时也是排序键。

搭配 Unique Mode 使用

DIMS 可以与 MARS3 Unique Mode 搭配使用:

CREATE TABLE latest_reading (
    value int NOT NULL
)
USING MARS3
  WITH (uniquemode=true)
  DIMS (device_id int NOT NULL, ts timestamp NOT NULL)
  DISTRIBUTED BY (device_id)
  ORDER BY (device_id, ts);

在 Unique Mode 场景下,如果维度列同时作为唯一键或排序键的一部分,应根据业务语义显式声明 NOT NULL 约束。

注意!
如果开启 Unique Mode,ORDER BY 子句中的第一个字段需要定义为 NOT NULL

使用引号标识符

如果维度列名包含空格、连字符或大小写敏感字符,可以使用双引号声明:

CREATE TABLE data (
    id int
)
USING MARS3
  DIMS ("capture time" timestamp, "sensor-ID" int)
  DISTRIBUTED BY (id)
  ORDER BY (id);

后续查询这些列时,也需要使用双引号引用:

SELECT "capture time", "sensor-ID"
FROM data;

查看维度列

使用 psql 查看

可以使用 \d+ 查看 MARS3 表的维度列信息:

\d+ my_table

示例输出如下:

                      Table "public.my_table"
 Column |            Type             | ...
--------+-----------------------------+-----
 ts     | timestamp without time zone | ...
 id     | integer                     | ...
 value  | numeric                     | ...
Distributed by: (id)
Order by: (id)
Options: dim_columns=ts,id, mars3options=nbuckets=3
Dimensions: ts, id

其中,Dimensions 字段展示当前表中声明的维度列。

查询系统目录

也可以通过系统目录查询某张表的维度列:

SELECT attname
FROM pg_attribute
WHERE attrelid = 'my_table'::regclass
  AND attnum > 0
  AND attoptions @> ARRAY['is_dimension=true']
ORDER BY attnum;

列顺序

使用 DIMS 创建表时,维度列在物理列顺序中排在普通列之前。

例如:

CREATE TABLE t (
    a int,
    b text
)
USING MARS3
  DIMS (c int, d text)
  DISTRIBUTED BY (c)
  ORDER BY (c);

该表的物理列顺序为:

c, d, a, b

因此,如果 INSERT 语句没有显式指定列名,需要按照物理列顺序写入:

INSERT INTO t VALUES (1, 'x', 10, 'hello');

更推荐显式指定列名,避免列顺序引起误写:

INSERT INTO t (c, d, a, b) VALUES (1, 'x', 10, 'hello');

使用限制

DIMS 子句存在以下限制:

限制项 说明
存储引擎限制 DIMS 仅支持 USING MARS3 的表,不支持 HEAP、AO 等其他存储引擎。
外部表限制 DIMS 不支持外部表。
空列表限制 DIMS () 是非法语法。
定义内容限制 DIMS 内部只允许列定义,不支持 LIKE 子句和表级约束。
名称冲突限制 维度列名不能与普通列名重复,也不能与其他维度列重名。
行为限制 DIMS 只声明维度语义,不会自动创建索引,也不会自动改变数据分布、排序或分区方式。

使用建议

  • 建议将业务中稳定、常用于筛选或标识数据主体的字段声明为维度列,例如设备 ID、采集时间、业务标签等。
  • 如果维度列经常用于点查、范围查询或聚合过滤,可以结合业务查询模式,将其同时设计为分布键、排序键或分区键。
  • 对于时间序列表,常见设计是将设备标识和时间字段声明为维度列,并根据查询模式选择合适的 DISTRIBUTED BYORDER BY
  • 建议在写入语句中显式指定列名,避免因维度列物理顺序靠前而导致写入值错位。