主键Primary Key

为了确保数据表中每一条记录的唯一性、数据的一致性和方便数据管理,您需要为表设置主关键字(Primary Key,简称主键或PK)。Hologres中主键与传统数据库主键特性一致,是表中记录的唯一标识,代表了表数据的唯一性。因此被设置为主键的字段是唯一的且是非空的,并且支持设置多个字段为主键。本文为您介绍在Hologres中为表设置主键。

主键介绍

在Hologres中,系统会自动在底层保存一个主键索引文件,采用行存结构存储,提供高速的KV(key- value)服务,索引文件的Key为表的主键PK,Value为RID(Row Identified,原名为unique_id)和聚簇索引(Clustering Key)。RID每次UPSERT自动生成,单调递增。主键索引文件能够实现高效的主键冲突判定并辅助数据文件定位。假如为表设置了PK,那么就可以通过PK在主键索引文件中快速定位到RID和Clustering Key,再通过RID和Clustering Key定位到数据所在的文件。

因此在Hologres中设置了主键,可以非常方便地支持实时数仓场景下的多种诉求:

  • 支持高性能的UPSERT或DELETE。

    Hologres具有传统数据库高性能Append Only类型的写入特性外,还可以通过主键实现高性能的整行写入更新、部分列写入更新。在进行写入更新时只需要根据主键更新,不需要全表扫描,从而达到高性能的UPSERT,同时也能保证数据的唯一性。写入更新的详细技术原理请参见Hologres写入技术揭秘

  • 支持高QPS的基于主键查询。

    表存储格式:列存、行存、行列共存一文中介绍:如果为表设置了PK,在基于PK的查询场景中,就能快速根据主键定位到整行数据,提升查询性能。尤其是当表设置为行存表时,主键默认为Clustering Key和Distribution Key,就能通过主键定位到数据文件,实现超高QPS的主键点查,且延迟在毫秒级,适用于实时风控、实时推荐等在线应用场景,详细原理请参见Hologres在线服务能力技术揭秘

使用建议

主键的设置尽量选择含有实际业务意义的字段,不建议将Serial类型的字段设置为主键,因为Serial类型在写入的时候是表锁,导致写入性能有损失,且随着数据的增长,长度容易溢出。

使用限制

  • 被设置为主键的字段是唯一且非空的列或者列组合,同时只能在一个语句里设置多列为表的主键。

  • 最多支持32个列组成的联合主键。

  • 不支持将FLOAT、DOUBLE、NUMERIC、ARRAY、JSON、JSONB、DATE及其他复杂数据类型的字段设置为主键。Hologres从 V1.3.22及以上版本支持将Date类型字段设为主键,如需将DATE类型字段设为主键,请先查看您Hologres实例版本后视情况升级实例,详情请参见实例配置实例升级

  • 行存表必须设置主键,行列共存表必须设置主键,列存表不要求有主键。

  • 不支持修改主键,如需修改主键请重新建表。

使用示例

以下为Hologres V2.1版本起的语法示例。如果您的实例为V2.0及以前版本,需要将DDL中的WITH (property = 'value')语句改为CALL set_table_property语句,详情请参见CREATE TABLE

  • 新建普通列存表并指定一个主键。

    • V2.1版本起支持的建表语法:

      CREATE TABLE tbl_1 (
          id bigint NOT NULL,
          name text NOT NULL,
          age bigint NOT NULL,
          class text,
          reg_timestamp timestamptz NOT NULL,
          PRIMARY KEY (id)
      )
      WITH (
          orientation = 'column',
          distribution_key = 'id',
          clustering_key = 'age',
          event_time_column = 'reg_timestamp',
          bitmap_columns = 'name,class',
          dictionary_encoding_columns = 'class:auto'
      );
    • 所有版本支持的建表语法:

      BEGIN;
      CREATE TABLE tbl_1 (
       id bigint NOT NULL,
       name text NOT NULL,
       age bigint,
       class text,
       reg_timestamp timesatmptz, 
      PRIMARY KEY (id)
      );
      CALL set_table_property('tbl_1', 'orientation', 'column');
      CALL set_table_property('tbl_1', 'distribution_key', 'id');
      CALL set_table_property('tbl_1', 'clustering_key', 'age');
      CALL set_table_property('tbl_1', 'event_time_column', 'reg_timestamp');
      CALL set_table_property('tbl_1', 'bitmap_columns', 'name,class');
      CALL set_table_property('tbl_1', 'dictionary_encoding_columns', 'class:auto');
      COMMIT;
  • 新建一个普通列存表并指定两个主键。

    • V2.1版本起支持的建表语法:

      CREATE TABLE tbl_1 (
          id bigint NOT NULL,
          name text NOT NULL,
          age bigint NOT NULL,
          class text NOT NULL,
          reg_timestamp timestamptz NOT NULL,
          PRIMARY KEY (id,age)
      )
      WITH (
          orientation = 'column',
          distribution_key = 'id',
          clustering_key = 'age',
          event_time_column = 'reg_timestamp',
          bitmap_columns = 'name,class',
          dictionary_encoding_columns = 'class:auto'
      );
    • 所有版本支持的建表语法:

      BEGIN;
      CREATE TABLE tbl_2 (
       id bigint NOT NULL,
       name text NOT NULL,
       age bigint NOT NULL,
       class text NOT NULL,
       reg_timestamp timestamptz NOT NULL,
      PRIMARY KEY (id,age)
      );
      CALL set_table_property('tbl_2', 'orientation', 'column');
      CALL set_table_property('tbl_2', 'distribution_key', 'id');
      CALL set_table_property('tbl_2', 'clustering_key', 'age');
      CALL set_table_property('tbl_2', 'event_time_column', 'reg_timestamp');
      CALL set_table_property('tbl_2', 'bitmap_columns', 'name,class');
      CALL set_table_property('tbl_2', 'dictionary_encoding_columns', 'class:auto');
      COMMIT;
  • 创建行存表并指定主键。

    • V2.1版本起支持的建表语法:

      CREATE TABLE public.tbl_row (
          id text NOT NULL,
          name text NOT NULL,
          class text,
          PRIMARY KEY (id)
      )
      WITH (
          orientation = 'row',
          distribution_key = 'id',
          clustering_key = 'id'
      );
    • 所有版本支持的建表语法:

      BEGIN;
      CREATE TABLE public.tbl_row (
          id text NOT NULL,
          name text NOT NULL,
          class text ,
      PRIMARY KEY (id)
      );
      CALL set_table_property('public.tbl_row', 'orientation', 'row');
      CALL set_table_property('public.tbl_row', 'clustering_key', 'id');
      CALL set_table_property('public.tbl_row', 'distribution_key', 'id');
      COMMIT;
  • 创建分区表并指定主键。

    • V2.1版本起支持的建表语法:

      BEGIN;
      CREATE TABLE public.tbl_parent(
        a text , 
        b int, 
        c timestamp, 
        d text,
        ds text,
        PRIMARY KEY (ds,b)
        )
       PARTITION BY LIST(ds)
       WITH ( orientation = 'column');
      CREATE TABLE public.tbl_child_1 PARTITION OF public.tbl_parent FOR VALUES IN('20221207');
      CREATE TABLE public.tbl_child_2 PARTITION OF public.tbl_parent FOR VALUES IN('20221208');
      COMMIT;
    • 所有版本支持的建表语法:

      BEGIN;
      CREATE TABLE public.tbl_parent(
        a text , 
        b int, 
        c timestamp, 
        d text,
        ds text,
        PRIMARY KEY (ds,b)
        )
        PARTITION BY LIST(ds);
      CALL set_table_property('public.tbl_parent', 'orientation', 'column');
      CREATE TABLE public.tbl_child_1 PARTITION OF public.tbl_parent FOR VALUES IN('20221207');
      CREATE TABLE public.tbl_child_2 PARTITION OF public.tbl_parent FOR VALUES IN('20221208');
      COMMIT;

相关文档