表结构设计
CREATE TABLE 语句用于在数据库中创建新表。以下是一些指引,以帮助您在 ProtonBase 中创建新表。
表的存储模式
ProtonBase 中的表包括三种存储模式:行存、列存和行列混存。每种存储方式都有其自己的优点和用途。
- 行存: 在行存下,单个行的数据存储在一起。这是传统关系数据库最常见的布局。表的默认存储方式是行存。
- 列存: 在列存下,每列的数据存储在一起。列存对于分析工作负载非常高效,因为您通常查询特定列而不是所有数据。它可以减少 I/O 并提高查询性能。
- 行列混存: 在某些情况下,您可能选择行列混存,结合了行存和列存。这在处理各种查询,如 HTAP 场景时,可能会有益。请注意,行列混存下的存储会更大。
表存储模式的选择取决于您应用程序的特定要求和查询模式。
-- 创建一张行存表 (默认存储模式).
CREATE TABLE row_t(
id int PRIMARY KEY,
name text,
age smallint,
gender char(1)
);
-- 创建一张列存表
CREATE TABLE columnar_t(
id int PRIMARY KEY,
name text,
age smallint,
gender char(1)
) USING columnar;
-- 创建一张行列混存表
CREATE TABLE hybrid_t(
id int PRIMARY KEY,
name text,
age smallint,
gender char(1)
) USING hybrid;
更多有关建表的语法说明,请参考CREATE TABLE
定义主键
主键(Primary Key,PK)是表中每一行的唯一标识符。大多数情况下,为了确保数据的唯一性和完整性,会在表上定义主键。设置主键时,请考虑以下事项:
- 唯一性:主键必须包含每一行的唯一值。ProtonBase 会自动强制执行此要求。
- 效率:选择一个经常用于查询和连接表的列或一组列。这有助于优化查询性能。如果主键中包含多列,主键中列的顺序会显著影响底层索引查找的效率。只有在先导列(最左侧)上存在约束时才会高效。具体规则是,在先导列上的等值约束,加上第一个不等值约束的列上的不等值约束,将被用于限制索引被扫描的部分。例如,假设主键是(a,b,c),查询条件为 WHERE a = 5 AND b >= 42 AND c < 77,那么索引将从具有 a = 5 和 b = 42 的第一个条目扫描,一直到具有 a = 5 的最后一个条目。
- 稳定性:尽量避免那些可能经常更改的列作为主键,因为这可能导致更新变慢。 要设置主键,请在表定义中使用 PRIMARY KEY 约束:
CREATE TABLE t(
id int PRIMARY KEY,
name text,
age smallint,
gender char(1)
);
在定义主键时,应避免以下一些不好的示例:
- 不要总是将自增 id 字段作为主键,特别是当 id 字段实际上并未在用户的所有查询中使用时。自增 id 字段会影响写入性能。
- 不要在单一单调列上定义主键,例如在自增列或按时间戳递增的列上,这会影响写入性能。
行存表
行存是表的默认模式,或者您也可以使用 using row 来指定表为行存。
CREATE TABLE row_t(
id int PRIMARY KEY,
name text,
age smallint,
gender char(1)
);
CREATE TABLE row_t(
id int PRIMARY KEY,
name text,
age smallint,
gender char(1)
) USING row;
列存表
您也可以使用 using columnar 来指定表为列存。
CREATE TABLE columnar_t(
id int PRIMARY KEY,
name text,
age smallint,
gender char(1)
) USING columnar;
行列混存表
您也可以使用 using hybrid 来指定表为行列混存。
CREATE TABLE hybrid_t(
id int PRIMARY KEY,
name text,
age smallint,
gender char(1)
) USING hybrid;
CREATE TABLE LIKE
基于现有表的表结构创建一个空表。创建一个空表,复制目标表的结构以及约束,如 NOT NULL。CREATE TABLE LIKE
语法通常用于数据库管理和维护任务,例如在一个数据库中创建与另一个表相同结构的临时表,或者将表的结构复制到另一个 schema 下。
CREATE TABLE t2(LIKE t INCLUDING ALL);
创建的时候,您可以同时指定表的存储模式:
CREATE TABLE t2(LIKE t INCLUDING ALL) USING columnar;
CREATE TABLE t2(LIKE t INCLUDING ALL) USING hybrid;
CREATE TABLE AS SELECT(CTAS)
从SELECT
语句创建表,使用CREATE TABLE AS SELECT
语句,您可以复制整个表、特定记录或仅表的结构。请注意,这个命令无法复制索引或约束,如 NOT NULL、主键、外键等。
CREATE TABLE t2 AS SELECT * FROM t WHERE age > 18;
自增表
要创建一个具有自动递增主键的表,您可以使用 SERIAL
数据类型作为主键列的数据类型(注:serial 确保了单调递增,但是会影响写入性能。尽量选用业务字段作为主键)。以下是一个示例:
> CREATE TABLE t(id serial PRIMARY KEY, b int);
CREATE TABLE
> INSERT INTO t(b) VALUES (1), (2), (4);
INSERT 0 3
> SELECT * FROM t;
id | b
----+---
1 | 1
2 | 2
3 | 4
(3 rows)
外键表
要创建一个具有外键约束的表,您可以使用以下示例。假设您有两个表,一个名为 "weather",另一个名为 "cities",并且您想确保在 "weather" 表中插入的行必须有一个在 "cities" 表中匹配的条目。
CREATE TABLE cities (
name varchar(80) PRIMARY KEY,
location point
);
CREATE TABLE weather (
city varchar(80) REFERENCES cities(name),
temp_lo int,
temp_hi int,
prcp real,
date date
);
分区表
分区通常用于提高查询性能和更有效地管理大量数据。分区表的介绍及例子详见这里。
修改表结构
支持在线修改表结构,简化运维工作,具体参考文档表结构修改。