Lakehouse 唯一键(UNIQUE)使用说明
唯一键约束概述
与传统数据库的重要区别
云器 Lakehouse 的 UNIQUE 约束是声明式约束(informational constraint),其行为与 MySQL、PostgreSQL 等传统数据库有本质差异:
- 默认不强制唯一性:默认模式(
DISABLE NOVALIDATE RELY
DISABLE NOVALIDATE RELY
)下,系统在 SQL 写入时不校验唯一性,重复值可以正常写入。
- 核心作用是查询优化:UNIQUE 约束主要用于向查询优化器声明列的数据语义(某列或某组列的值唯一),帮助优化器在去重消除、行数估算、Join 优化等场景做出更优的执行计划。
- 应用层保证唯一性:如果业务上需要严格唯一,应由数据写入端自行保证,不能依赖 UNIQUE 约束。
UNIQUE
UNIQUE
约束用于声明表中某一列或某几列的组合值是唯一的。与主键(PRIMARY KEY)不同,UNIQUE 约束:
- 允许列值为 NULL(主键列强制 NOT NULL);
- 一张表可以定义多个 UNIQUE 约束(主键只能有一个);
- 不作为实时写入(CDC UPSERT/DELETE)的操作键。
UNIQUE 约束只能在建表(CREATE TABLE)时指定,不支持通过 ALTER TABLE 添加。
语法
UNIQUE 约束支持列级和表级两种写法,均可附加约束修饰符。
列级写法
CREATE TABLE t (
id int UNIQUE,
name string
);
表级写法
表级写法支持单列和多列组合(复合唯一键):
-- 单列
CREATE TABLE t (
id int,
name string,
UNIQUE(id)
);
-- 复合唯一键
CREATE TABLE t (
a int,
b int,
UNIQUE(a, b)
);
约束修饰符
UNIQUE 约束可附加三组修饰符,顺序固定(与 PRIMARY KEY、FOREIGN KEY 一致):
UNIQUE [ENABLE | DISABLE] [VALIDATE | NOVALIDATE] [RELY | NORELY]
| 修饰符 | 含义 | 默认值 |
|---|
ENABLE
ENABLE / DISABLE
DISABLE | 是否对后续写入强制校验 | DISABLE
DISABLE |
VALIDATE
VALIDATE / NOVALIDATE
NOVALIDATE | 是否要求数据满足约束 | NOVALIDATE
NOVALIDATE |
RELY
RELY / NORELY
NORELY | 优化器是否信任并使用该约束做查询优化 | RELY
RELY |
不带任何修饰符时,UNIQUE 约束的默认行为是 DISABLE NOVALIDATE RELY
DISABLE NOVALIDATE RELY
。
默认行为:声明式约束(不去重)
默认的
DISABLE NOVALIDATE RELY
DISABLE NOVALIDATE RELY
模式下,UNIQUE 约束仅作为元数据记录,
不阻止重复值写入:
CREATE TABLE uk_demo (id int UNIQUE, name string);
-- 查看约束
DESC EXTENDED uk_demo;
-- unique_keys: ((id) DISABLE NOVALIDATE RELY)
-- 重复 id 均可写入
INSERT INTO uk_demo VALUES(1, 'a');
INSERT INTO uk_demo VALUES(1, 'b');
SELECT * FROM uk_demo;
-- 1 | a
-- 1 | b (重复值未被阻止)
-- 允许多个 NULL
INSERT INTO uk_demo VALUES(NULL, 'c');
INSERT INTO uk_demo VALUES(NULL, 'd');
-- 均写入成功
RELY 与优化器
RELY
RELY
(默认)告诉优化器可以信任该约束并据此优化查询,即使约束并未在写入时强制校验。优化器会利用 RELY 的唯一键进行:
- 去重消除(DISTINCT / GROUP BY 的化简);
- 行数与 NDV(distinct value 数)估算;
- Join 基数估算与计划选择。
如果数据实际上并不满足唯一性,而约束又声明为 RELY,可能导致优化器产生错误的结果。此时应使用
NORELY
NORELY
让优化器忽略该约束:
CREATE TABLE uk_demo (id int UNIQUE NORELY, name string);
-- unique_keys: ((id) DISABLE NOVALIDATE NORELY)
修饰符的实际生效情况
实测中各修饰符组合的实际行为如下:
| 声明方式 | DESC EXTENDED 显示 | SQL 写入行为 |
|---|
UNIQUE
UNIQUE (默认) | DISABLE NOVALIDATE RELY
DISABLE NOVALIDATE RELY | 允许重复、允许多个 NULL |
UNIQUE ENABLE
UNIQUE ENABLE | ENABLE NOVALIDATE RELY
ENABLE NOVALIDATE RELY | 允许重复(无 VALIDATE 不校验) |
UNIQUE NORELY
UNIQUE NORELY | DISABLE NOVALIDATE NORELY
DISABLE NOVALIDATE NORELY | 允许重复,且优化器忽略 |
多个 UNIQUE
UNIQUE | 各自 DISABLE NOVALIDATE RELY
DISABLE NOVALIDATE RELY | 允许 |
⚠️ 强制唯一性(ENABLE VALIDATE
ENABLE VALIDATE
)当前不可用
声明
UNIQUE ... ENABLE VALIDATE
UNIQUE ... ENABLE VALIDATE
时,建表会成功(DESC 显示
ENABLE VALIDATE RELY
ENABLE VALIDATE RELY
,并自动生成 HASH 分桶与排序键),但对该表执行 INSERT 会报编译器错误:
CZLH-65000: ... Table should have primary keys/unique keys
该限制与列是否声明 NOT NULL 无关。如果需要写入时强制去重,请使用主键(PRIMARY KEY)而非 UNIQUE 约束。 详见主键使用说明。
与主键(PRIMARY KEY)的关系
CREATE TABLE t (id int PRIMARY KEY, code int UNIQUE ENABLE VALIDATE);
-- CZLH-42000: cannot enforce UNIQUE constraint with an enforced PRIMARY KEY
| 对比项 | PRIMARY KEY | UNIQUE |
|---|
| 每表数量 | 至多 1 个 | 可多个 |
| 列可空性 | 强制 NOT NULL | 允许 NULL(可多个 NULL) |
| 实时写入(CDC)去重键 | 是 | 否 |
| 默认修饰符 | ENABLE VALIDATE RELY
ENABLE VALIDATE RELY | DISABLE NOVALIDATE RELY
DISABLE NOVALIDATE RELY |
| 主要用途 | CDC 去重 + 查询优化 | 查询优化(声明式) |
建表时的校验规则
建表时系统会对 UNIQUE 约束做以下校验:
- 同一约束内列名不能重复:
UNIQUE(a, a)
UNIQUE(a, a)
报错。
- 约束不能冗余:若某个 UNIQUE 约束与主键相同、或是另一个唯一键(或主键)的超集,会报
unnecessary unique key
unnecessary unique key
。
- 至多一个强制约束:多个
ENABLE VALIDATE
ENABLE VALIDATE
约束(含主键)会报错。
使用建议
- 把 UNIQUE 当作给优化器的提示:当你确知某列在业务上唯一(如从上游系统同步的业务主键),用 UNIQUE 声明可以帮助优化器生成更优的计划。
- 若声明的列实际可能存在重复,使用
NORELY
NORELY
避免优化器据此做错误化简。
- 需要在写入时真正强制去重时,使用主键(PRIMARY KEY)并配合实时写入接口,而不是 UNIQUE 约束。
参考