当列值是 84 字节文本字段时,postgres 中保持列唯一的最有效方法是啥?
Posted
技术标签:
【中文标题】当列值是 84 字节文本字段时,postgres 中保持列唯一的最有效方法是啥?【英文标题】:Most efficient way in postgres to keep a column unique when that column value is an 84 byte text field?当列值是 84 字节文本字段时,postgres 中保持列唯一的最有效方法是什么? 【发布时间】:2020-07-25 20:39:21 【问题描述】:计划使用哈希索引,但我还想有效地保持列的唯一性并在数据库中强制执行此操作。但是我真的不想构建一个 btree 并将我的数据库的大小加倍(整个表是一个文本字段、一个 bigint 和一个 int)。有没有办法编写约束以将哈希索引与数据字段的比较结合起来?我知道我不能在哈希索引上使用 UNIQUE 限定符,但这真的很好!有没有办法编写一个使用索引来获得唯一约束的约束,即使索引本身不支持它?
Postgres 版本 11+
http://rhaas.blogspot.com/2017/09/postgresqls-hash-indexes-are-now-cool.html
【问题讨论】:
确保唯一性的唯一方法是使用 btree 索引。如果你需要它,你将不得不忍受更大的索引大小。 【参考方案1】:编辑添加(2021 年 10 月 28 日):
这可以通过排除约束来消除对主键列的需求:
# create table faux_unique (
data text not null,
exclude using hash (data with =)
);
CREATE TABLE
# insert into faux_unique values('abc');
INSERT 0 1
# insert into faux_unique values('def');
INSERT 0 1
# insert into faux_unique values('abc');
ERROR: conflicting key value violates exclusion constraint "faux_unique_data_excl"
DETAIL: Key (data)=(abc) conflicts with existing key (data)=(abc).
# update faux_unique set data = 'abc' where data = 'def';
ERROR: conflicting key value violates exclusion constraint "faux_unique_data_excl"
DETAIL: Key (data)=(abc) conflicts with existing key (data)=(abc).
# select * from faux_unique;
┌──────┐
│ data │
├──────┤
│ abc │
│ def │
└──────┘
(2 rows)
原始答案,如下
您可以使用哈希索引来模拟带有check
约束的unique
约束,但您需要对表进行PK,否则该约束将无法捕获由于update
而导致的违规。
create table faux_unique (id serial primary key, data text not null);
create index faux_unique_hash_idx on faux_unique using hash (data);
create function is_unique_check(v_data text, v_id integer) returns boolean as $$
select count(*) = 0
from faux_unique
where data = v_data
and id != v_id;
$$ language sql;
alter table faux_unique add constraint faux_unique_check check (is_unique_check(data, id));
运行一些测试数据:
insert into faux_unique (data) values ('first'), ('second'), ('third');
INSERT 0 3
insert into faux_unique (data) values ('first');
ERROR: new row for relation "faux_unique" violates check constraint "faux_unique_check"
DETAIL: Failing row contains (4, first).
update faux_unique set data = 'second' where data = 'first';
ERROR: new row for relation "faux_unique" violates check constraint "faux_unique_check"
DETAIL: Failing row contains (1, second).
update faux_unique set data = 'second' where id = 1;
ERROR: new row for relation "faux_unique" violates check constraint "faux_unique_check"
DETAIL: Failing row contains (1, second).
insert into faux_unique (data) values ('fourth');
INSERT 0 1
【讨论】:
以上是关于当列值是 84 字节文本字段时,postgres 中保持列唯一的最有效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
Hive : 当列值由分隔符 (~) 分隔时,将单个记录扩展为多个记录
当列值更改时,如何将组号添加到 SQL Server 2012 中的顺序记录?
ExtJS 4 - 当列编辑器是组合框时如何避免网格列值变为空?