Postgres:这个僵局来自哪里?

时间:2016-01-20 23:26:34

标签: postgresql deadlock postgresql-9.3

pg_log:

2016-01-20 23:00:31 UTC ERROR:  deadlock detected
2016-01-20 23:00:31 UTC DETAIL:  
    Process 2696 waits for RowShareLock on relation 1849109 of database 1847373; blocked by process 2919.
    Process 2919 waits for AccessExclusiveLock on relation 1848698 of database 1847373; blocked by process 2696.
    Process 2696:
                INSERT INTO install_session (
                    [..]
                ) VALUES (
                    [..]
                )

    Process 2919: DROP TABLE IF EXISTS install_view_2015_11_20
2016-01-20 23:00:31 UTC HINT:  See server log for query details.

查询上述关系给了我:

select * from pg_class where oid = 1849109;
> install
select * from pg_class where oid = 1848698; 
> app

问题:

  1. 为什么会发生僵局? INSERTDROP的目标是两个不同的表格。
  2. 其他两个关系/表(安装,应用程序)与它有什么关系?
  3. Postgres 9.3

    更新

    我确实有triggers

    CREATE OR REPLACE FUNCTION insert_install_session()
            RETURNS TRIGGER AS $$
            BEGIN
                EXECUTE 'INSERT INTO install_session_'
                    || to_char(NEW.created, 'YYYY_MM_DD') || 
                    ' SELECT ($1).*'
                USING NEW;
                RETURN NULL;
            END;
            $$
            LANGUAGE PLPGSQL
    
      CREATE TRIGGER trigger_insert_install_session
            BEFORE INSERT ON install_session
            FOR EACH ROW EXECUTE PROCEDURE insert_install_session()
    
    来自所有分区的

    foreign keys(在本例中为install_session_XXXX_XX_XX和install_view_XXXX_XX_XX)引用表appinstall

    这使得事情变得更加清晰,但我仍然不明白为什么DROP命令需要锁定除应该删除的表之外的任何表。

1 个答案:

答案 0 :(得分:1)

我做了以下实验:

test=> CREATE TABLE aa( x int primary key );
CREATE TABLE
test=> CREATE TABLE bb( y int primary key, x int references aa(x) );
CREATE TABLE
test=> BEGIN;
BEGIN
test=> DROP TABLE bb;
DROP TABLE
test=>

在另一场会议中:

test=> select locktype, relation, relname,
test->        transactionid, mode, granted
test-> from pg_locks p
test-> left join pg_class c on p.relation = c.oid
test-> where locktype = 'relation'
test-> ;
 locktype | relation |              relname              | transactionid |        mode         | granted
----------+----------+-----------------------------------+---------------+---------------------+---------
  .........
  .........
  .........
  .........
 relation |    24739 | aa                                |               | AccessExclusiveLock | t
 relation |    24744 | bb                                |               | AccessExclusiveLock | t
(13 wierszy)

似乎丢弃表B需要对表'B'和'A'进行独占锁定。

为什么PostgeSQL需要将'A'与'B'区分开来?我真的不知道。
我认为我们能做的最好的事情就是将这一事实与生活相协调。


如果我们知道PostgreSQL需要对两个表进行独占锁定,那么死锁的原因现在已经很清楚了:

  • 第一个事务中的第一个插入在表A上放置一个共享锁
  • 要运行DROP TABLE B的第二个事务必须获取表A上的独占锁,并且必须等待事务#1
  • 第一个事务运行第二个插入,这也需要表A上的共享锁,并且必须等待事务#2 - > bang:deadlock



为了避免死锁,在执行第一次插入之前,在第一个事务中将表A放在AccessExclusiveLock上。