我有一个奇怪的情况,从日志中看到:
Process 37278 waits for ExclusiveLock on advisory lock [16421,999999,12864385,2]; blocked by process 53807.
Process 53807 waits for ExclusiveLock on advisory lock [16421,999999,12864395,2]; blocked by process 37278.
Process 37278: SELECT * FROM zel_api.insert_event ($1 ,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24)
Process 53807: SELECT * FROM zel_api.insert_event ($1 ,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24)",
"See server log for query details.",,,"SQL statement ""SELECT pg_advisory_xact_lock(999999, format('zel_event.%I', p_table_name)::regclass::oid::integer)""
这本身就已经很奇怪了,因为它看起来像是两个进程阻塞了同一个咨询锁,但实际上都没有抓住它。
尝试获取锁的函数如下:
CREATE OR REPLACE FUNCTION zel_event.create_new_partition(
p_table_name text
)
RETURNS void AS
$BODY$
DECLARE
_schema text;
BEGIN
IF NOT EXISTS (table from catalog)
THEN
PERFORM pg_advisory_xact_lock(999999, format('zel_event.%I', p_table_name)::regclass::oid::integer);
IF NOT EXISTS (table from catalog)
THEN
EXECUTE format('
CREATE TABLE %1$I.%2$I (
LIKE zel_event.%2$I INCLUDING ALL
) INHERITS (zel_event.%2$I)', _schema, p_table_name);
END IF;
END IF;
RETURN;
END;
$BODY$
LANGUAGE plpgsql
SECURITY DEFINER;
在我看来,这里没有任何“经典”死锁原因,因为只有一种逻辑......
其背后的想法是按需创建新表,其中需求可以从多个连接以非常高的频率出现。当插入函数执行针对父表的插入时调用它,并由调度程序触发器转移到适当的子表。
这是交易的样子:
INSERT INTO parent (zel_api.insert_event())
|
trigger
|
+----> child exists? ---no---> CREATE TABLE child
| |
yes |
| |
V V
INSERT INTO child (zel_event.create_new_partition())
PostgreSQL 版本为 9.2
了解这是如何发生的(当然还有减轻),这将是非常有趣的。
这不是同一个咨询锁。您的日志提到第一个进程与第二个进程不同的表 oid(相差 10)。这看起来像是一个典型的死锁情况,其中两个进程正在以不同的顺序寻求相同的锁。第一个中的第三个数字是 12864385,而第二个中的第三个数字是 12864395。
所以我怀疑这两个进程都试图创建相同的分区,只是顺序不同,所以它们会死锁。
我发现在这种令人费解的情况下有帮助的一件事是在整个数字系列中一次遍历并比较一个数字,因为使用建议锁很容易像这样巧妙地错过一个数字。