我们有一个PostgreSQL函数已经运行了很长一段时间就好了,但最近它因为未知原因而开始挂起......
我挖掘了函数,函数的第一行是“锁定”;
注释掉该行后,该函数运行得非常好,但允许该表锁运行会导致我的函数,因此我的应用程序无限期地锁定(冻结)...
代码本身有点傻(这是我们刚刚维护的遗留代码)...所以请不要问为什么这个代码运行...只要知道它抓取一个唯一的ID用于一个给定应用程序中的一组函数。我也知道,当它用完唯一ID时会出现问题......我们会定期清除这些ID,因此总会有可用的ID。
declare
tmp int4;
begin
lock table1; --the offending line
for g in 1 .. 999 loop
select g_id into tmp from table1 where g_id = g;
if not found then
insert into table1 (g_id, type, date, status) values (g, 'type', current_timestamp, 'w');
return g;
end if;
end loop;
raise exception 'unable to find unique id';
return 0;
end;
同样,如果没有“lock”命令,该函数会运行,但是一旦我允许该命令运行它就会挂起。有谁见过PostgreSQL的类似问题并有解决方案?
一旦函数挂起,请查看pg_locks表以查看持有锁的内容。从那里,您应该能够找出死锁的位置。请记住,锁定一直持续到事务结束。
由于您正在进行插入操作,因此需要锁定以避免在获取空闲ID并将其插入表中时出现争用情况。如果应用程序可以处理它,请考虑使用序列来生成id。
正如“a_horse_with_no_name”所指出的,这是一种寻找新id的可怕方式。 SQL是基于集合设置的,因此使用set操作来查找未使用的ID。
举例来说:
首先是测试数据表。你不需要这个,因为你使用自己的table1。
create temp table table1 (g_id integer);
insert into table1
select x from generate_series(1,999) x
where random() < 0.10;
获取未使用的ID:
select
generate_series(1,999) new_id
except
select g_id from table1
limit 1;
如果您需要最低的未使用ID,请使用:
with unused as (
select
generate_series(1,999) new_id
except
select g_id from table1
)
select new_id from unused order by new_id limit 1;