我在 Postgres 中有一个多对多连接表,我想索引到 A)提高性能(显然)和 B)强制唯一性。例如:
a_id | b_id
1 | 2 <- okay
1 | 3 <- okay
2 | 3 <- okay
1 | 3 <- not okay (same as row 2)
是否可以在两列上建立一个索引来强制值的唯一性?我应该使用什么类型的索引?
我在 Postgres 中有一个多对多连接表,我想索引到 A)提高性能(显然)和 B)强制唯一性。例如:
a_id | b_id
1 | 2 <- okay
1 | 3 <- okay
2 | 3 <- okay
1 | 3 <- not okay (same as row 2)
是否可以在两列上建立一个索引来强制值的唯一性?我应该使用什么类型的索引?
如果该唯一键是主键,请执行此操作:
create table tbl(
a_id int not null,
b_id int not null,
constraint tbl_pkey primary key(a_id,b_id)
);
如果该唯一键是非主键,请执行此操作:
create table tbl(
-- other primary key here, e.g.:
-- id serial primary key,
a_id int not null,
b_id int not null,
constraint tbl_unique unique(a_id,b_id)
);
如果您有现有表,请改为执行以下操作:
alter table tbl
add constraint tbl_unique unique(a_id, b_id)
该更改表显示此消息:
NOTICE: ALTER TABLE / ADD UNIQUE will create implicit index "tbl_unique" for table "tbl"
Query returned successfully with no result in 22 ms.
如果您想删除该约束(您可能希望将 3 个字段的组合设为唯一):
ALTER TABLE tbl DROP CONSTRAINT tbl_unique;
关于索引,来自 Postgres doc:
当为表定义唯一约束或主键时,PostgreSQL 会自动创建唯一索引
来源:http ://www.postgresql.org/docs/9.1/static/indexes-unique.html
如果唯一性取决于某些规则,则应使用CREATE UNIQUE INDEX
,例如:
鉴于这种:
CREATE TABLE tbl
(
a_id integer NOT NULL,
b_id integer NULL
);
alter table tbl
add constraint tbl_unique unique(a_id, b_id);
该唯一可以捕获这些重复项,这将被数据库拒绝:
insert into tbl values
(1,1),
(1,1);
然而, UNIQUE CONSTRAINT 无法捕获重复的空值。Nulls 作为未知数,它们作为通配符,这就是为什么它允许在唯一约束中有多个空值。这将被数据库接受:
insert into tbl values
(1,1),
(1,null), -- think of this null as wildcard, some real value can be assigned later.
(1,null); -- and so is this. that's why both of these nulls are allowed
想想UNIQUE CONSTRAINT
它允许延迟唯一性,因此接受上面的空值。
如果您只希望每个 a_id 有一个通配符(null b_id),则除了唯一约束之外,您还需要添加一个UNIQUE INDEX
. UNIQUE CONSTRAINT 不能对它们有表达式。 INDEX
并且UNIQUE INDEX
可以。这将是您拒绝多个 null 的完整 DDL;
这将是您完整的 DDL:
CREATE TABLE tbl
(
a_id integer NOT NULL,
b_id integer NULL
);
alter table tbl
add constraint tbl_unique unique(a_id, b_id);
create unique index tbl_unique_a_id on tbl(a_id) where b_id is null;
这将被您的数据库现在拒绝:
insert into tbl values
(1,1),
(1,null),
(1,null);
这将被允许:
insert into tbl values
(1,1),
(1,null);
相关http://www.ienablemuch.com/2010/12/postgresql-said-sql-server2008-said-non.html
除了使用 @Michael Buen 解释的PRIMARY KEY
andUNIQUE
语法之外,您还可以创建一个显式索引:
CREATE UNIQUE INDEX foo_a_b ON tbl(a_id, b_id);
这只是一个普通的多列 b 树索引(这正是 KEY 语法隐式创建的)。