为了确保数据表中每一条记录的唯一性、数据的一致性和方便数据管理,您需要为表设置主关键字(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类型在写入的时候是表锁,导致写入性能有损失,且随着数据的增长,长度容易溢出。
使用限制
使用示例
以下为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;
相关文档
根据业务查询场景设置合适的表属性指南,请参见场景化建表调优指南。
Key/Value查询场景建表和查询最佳实践,请参见Key/Value查询场景最佳实践。