ram*_*sus 2 postgresql index-tuning many-to-many
我需要对 INSERT 和 UPDATE 操作实施唯一检查,但我更愿意避免在我的表上创建大量唯一索引(现在约为 12Gb)。现在我有唯一的部分索引并且它工作得很好,除了一件事 - 它需要大量的 SSD 空间。我不需要使用这个索引的 SELECT 操作,我只需要检查数据的唯一性。
我阅读了这个和这个讨论,我明白唯一约束和唯一索引之间没有真正的区别,除了部分条件,它只能用于索引。
有没有办法做到这一点?
更新:
我的例子是带有历史选项的多对多关系表的模式。此选项由 2 个附加字段time_from
和time_to
. 他们正在存储进入和离开关系的时间。为了数据一致性,我创建了 4 个额外的部分唯一索引(见下文)。
现在该表包含 1 162 010 000 行。以及每个索引的表的整体空间:
vkontakte_wall_post_likes_users - 57 GB
vkontakte_wall_post_like_users_post_id - 24 GB
vkontakte_wall_post_like_users_time_to_2col_uniq - 24 GB
vkontakte_wall_post_like_users_pkey - 24 GB
vkontakte_wall_post_like_users_user_id - 24 GB
vkontakte_wall_post_like_users_time_to_3col_uniq - 846 MB
vkontakte_wall_post_like_users_time_from_2col_uniq - 8192 bytes
vkontakte_wall_post_like_users_id_seq - 8192 bytes
Run Code Online (Sandbox Code Playgroud)
架构:
CREATE TABLE vkontakte_wall_post_likes_users
(
id integer NOT NULL DEFAULT nextval('vkontakte_wall_post_like_users_id_seq'::regclass),
post_id integer NOT NULL,
user_id integer NOT NULL,
time_from timestamp with time zone,
time_to timestamp with time zone,
CONSTRAINT vkontakte_wall_post_like_users_pkey PRIMARY KEY (id),
CONSTRAINT post_id_refs_id_3979681bdf0b31a3 FOREIGN KEY (post_id)
REFERENCES vkontakte_wall_post (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED,
CONSTRAINT user_id_refs_id_73bdbaad8e08aee5 FOREIGN KEY (user_id)
REFERENCES vkontakte_users_user (remote_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED
)
WITH (
OIDS=FALSE
);
ALTER TABLE vkontakte_wall_post_likes_users
OWNER TO manufacture;
CREATE INDEX vkontakte_wall_post_like_users_post_id
ON vkontakte_wall_post_likes_users
USING btree
(post_id);
CREATE UNIQUE INDEX vkontakte_wall_post_like_users_time_from_2col_uniq
ON vkontakte_wall_post_likes_users
USING btree
(post_id, user_id)
WHERE time_from IS NULL;
CREATE UNIQUE INDEX vkontakte_wall_post_likes_users_time_from_3col_uniq
ON vkontakte_wall_post_likes_users
USING btree
(post_id, user_id, time_from)
WHERE time_from IS NOT NULL;
CREATE UNIQUE INDEX vkontakte_wall_post_like_users_time_to_2col_uniq
ON vkontakte_wall_post_likes_users
USING btree
(post_id, user_id)
WHERE time_to IS NULL;
CREATE UNIQUE INDEX vkontakte_wall_post_like_users_time_to_3col_uniq
ON vkontakte_wall_post_likes_users
USING btree
(post_id, user_id, time_to)
WHERE time_to IS NOT NULL;
CREATE INDEX vkontakte_wall_post_like_users_user_id
ON vkontakte_wall_post_likes_users
USING btree
(user_id);
Run Code Online (Sandbox Code Playgroud)
如果您想有效地确保数据的唯一性,则无法避免创建唯一索引。唯一索引对于 PostgreSQL 在并发插入、更新和删除时强制执行唯一性是必要的。
唯一索引支持唯一约束;创建唯一约束时,会自动为您创建唯一索引。
强制唯一性的唯一其他方法是LOCK TABLE mytable IN EXCLUSIVE MODE
在对表进行任何可能影响您希望使其唯一的列的更改之前进行。这样您就不必创建唯一索引,但作为交换,您一次只能有一个事务更改表。仅当它检测到唯一列中的更改时,您才能从触发器执行此操作,但随后您会遭受会导致频繁死锁的锁升级。
真的,唯一索引是这里的方法。
您可以通过使用CREATE UNIQUE INDEX ... CONCURRENTLY
然后使用ALTER TABLE ... ADD CONSTRAINT ...
指定用于UNIQUE
约束的已创建索引的版本来减轻所需锁的影响。