我有一个PostgreSQL表,可以简化为:
CREATE TABLE car(
garage_id uuid,
number integer
);
我需要在每个车库中,每辆车都有一个唯一的整数(Car N°1,Car N°2)。
序列的第一个想法
我的第一个想法是通过触发器为每个车库创建PostgreSQL序列,然后当我插入汽车时,我只需要为车库创建的序列调用nextval。 (如看过here)
问题在于,对于每个车库,我需要创建一个序列。我的车库表很快会增长到1M行,根据这个帖子:Maximum number of sequences that can be created,过多的PostgreSQL序列确实会损害性能并使pgdump失败。
第二个想法
我发现了另一个想法on stackoverflow。
第二个想法是创建另一个像
的表CREATE TABLE garage_number(
garage_id uuid,
max_number integer
);
此表将保留最大车号,然后在每个插页中我们选择车库的max_number,并更新车库的max_number。
问题:目前它在并发方面不起作用(如果同时插入,则2辆车可以使用相同的号码)。
您是否知道我如何才能使其成为交易证明并且大规模工作?也许锁定garage_number表?
非常感谢你的帮助,
答案 0 :(得分:2)
" 我如何才能使其成为交易证明并且大规模工作" - 你不能。最好的办法是尽量减少通过非序列方法生成数字时所需的锁定。
你的garage_number
表可用于此,但我实际上不会在实际车库表上使用max()
,而是这样:
create or replace function next_car_number(p_garage uuid)
returns integer
as
$$
update garage_number
set max_number = max_number + 1
where garage_id = p_garage
returning max_number;
$$
language sql;
当然,您需要初始化garage_number
一次,并且每次创建新车库时都需要在该表中插入一个新行(0
的值为{{ 1}})
然后要分配一个新车号,您可以使用以下内容:
max_number
该车库的行将被锁定,直到该插入被提交,并且在此之前没有其他使用相同功能的插件可以完成。一旦提交,任何等待的事务都将看到新值。
在插入新车之前,您需要生成(并知道)车库的UUID - 但我猜是因为{引用了另一个名为insert into car
(garage, number)
values
('a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11', next_car_number('a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11'));
的表。 {1}}表,车库PK在插入新车时已经知道了。
这仍然序列化对"生成器的访问"对于单个车库,但会比为每个插入
运行garage
查询更快
答案 1 :(得分:0)
如果你没有在一次交易中插入几辆汽车,也许值得尝试txid_current()
?这个号码将与其他交易隔离开来,并且是唯一的。唯一明显但在这里 - 它不会是顺序的(你不能预测步骤,因为它取决于你执行你的交易量)。
insert into car
(garage, number)
values
('a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11', txid_current());
当然,如果您在同一事务中多次运行上述语句,它将无效,因为txid_current()
会相同。但是如果你将每个插入分开 - 这可能会起作用
https://www.postgresql.org/docs/current/static/functions-info.html