根据我对文档的理解,以下定义是等价的:

create table foo (
    id serial primary key,
    code integer,
    label text,
    constraint foo_uq unique (code, label));

create table foo (
    id serial primary key,
    code integer,
    label text);
create unique index foo_idx on foo using btree (code, label);    

然而,Postgres 9.4手册中的注释说:

向表中添加唯一约束的首选方法是ALTER table…添加约束。使用索引来强制惟一的约束 可以被认为是一个不应该被认为是实现细节的实现吗 直接访问。

(编辑:此说明已从Postgres 9.5的手册中删除。)

仅仅是风格的问题吗?选择其中一个变量的实际后果是什么(例如在性能方面)?


当前回答

有一件非常小的事情,只能使用约束而不能使用索引,那就是使用ON冲突ON约束子句(另见此问题)。

这行不通:

CREATE TABLE T (a INT PRIMARY KEY, b INT, c INT);
CREATE UNIQUE INDEX u ON t(b);

INSERT INTO T (a, b, c)
VALUES (1, 2, 3)
ON CONFLICT ON CONSTRAINT u
DO UPDATE SET c = 4
RETURNING *;

它产生:

[42704]: ERROR: constraint "u" for table "t" does not exist

将索引转换为约束:

DROP INDEX u;
ALTER TABLE t ADD CONSTRAINT u UNIQUE (b);

INSERT语句现在可以工作了。

其他回答

唯一性是一个限制。它恰好是通过创建来实现的 唯一的索引,因为一个索引能够很快地搜索所有现有的 值,以确定给定值是否已经存在。 从概念上讲,索引是一个实现细节,惟一性也应该是 只与约束相关联。

全文

所以速度性能应该是一样的

我遇到的另一件事是,您可以在唯一索引中使用sql表达式,但不能在约束中使用。

所以,这是行不通的:

CREATE TABLE users (
    name text,
    UNIQUE (lower(name))
);

但下面的做法是可行的。

CREATE TABLE users (
    name text
);
CREATE UNIQUE INDEX uq_name on users (lower(name));

使用UNIQUE INDEX与UNIQUE CONSTRAINT的另一个优点是,您可以轻松地并发地删除/创建索引,而使用CONSTRAINT则不行。

由于许多人已经提供了唯一索引相对于唯一约束的优点,这里有一个缺点:唯一约束可以延迟(仅在事务结束时检查),唯一索引不能。

SELECT a.phone_number,count(*) FROM public.users a
Group BY phone_number Having count(*)>1;

SELECT a.phone_number,count(*) FROM public.retailers a
Group BY phone_number Having count(*)>1;

select a.phone_number from users a inner join users b
on a.id <> b.id and a.phone_number = b.phone_number order by a.id;


select a.phone_number from retailers a inner join retailers b
on a.id <> b.id and a.phone_number = b.phone_number order by a.id
DELETE FROM
    users a
        USING users b
WHERE
    a.id > b.id
    AND a.phone_number = b.phone_number;
    
DELETE FROM
    retailers a
        USING retailers b
WHERE
    a.id > b.id
    AND a.phone_number = b.phone_number;
    
CREATE UNIQUE INDEX CONCURRENTLY users_phone_number 
ON users (phone_number);

验证:

insert into users(name,phone_number,created_at,updated_at) select name,phone_number,created_at,updated_at from users