2012-01-26 3 views
5

때때로 postgresql이 오류 교착 상태를 발생시키는 경우가 있습니다.postgresql 교착 상태

테이블에 설정된 트리거가 FOR UPDATE로 설정되었습니다. 테이블 코멘트에

2012-01-26 17:21:06 MSK ERROR: deadlock detected 
2012-01-26 17:21:06 MSK DETAIL: Process 2754 waits for ExclusiveLock on tuple (40224,15) of relation 735493 of database 734745; blocked by process 2053. 
Process 2053 waits for ShareLock on transaction 25162240; blocked by process 2754. 
Process 2754: INSERT INTO comment (user_id, content_id, reply_id, text) VALUES (1756235868, 935967, 11378142, 'text1') RETURNING comment.id; 
Process 2053: INSERT INTO comment (user_id, content_id, reply_id, text) VALUES (4071267066, 935967, 11372945, 'text2') RETURNING comment.id; 
2012-01-26 17:21:06 MSK HINT: See server log for query details. 
2012-01-26 17:21:06 MSK CONTEXT: SQL statement "SELECT comments_count FROM content WHERE content.id = NEW.content_id FOR UPDATE" 
PL/pgSQL function "increase_comment_counter" line 5 at SQL statement 
2012-01-26 17:21:06 MSK STATEMENT: INSERT INTO comment (user_id, content_id, reply_id, text) VALUES (1756235868, 935967, 11378142, 'text1') RETURNING comment.id; 

그리고 트리거 :

표 주석 :

http://pastebin.com/L1a8dbn4

로그 (INSERT 문장이의 cutted됩니다)

CREATE OR REPLACE FUNCTION increase_comment_counter() RETURNS TRIGGER AS $$ 
DECLARE 
comments_count_var INTEGER; 
BEGIN 
    SELECT INTO comments_count_var comments_count FROM content WHERE content.id = NEW.content_id FOR UPDATE; 
    UPDATE content SET comments_count = comments_count_var + 1, last_comment_dt = now() WHERE content.id = NEW.content_id; 
    RETURN NEW; 
END; 
$$ LANGUAGE plpgsql; 



CREATE TRIGGER increase_comment_counter_trigger AFTER INSERT ON comment FOR EACH ROW EXECUTE PROCEDURE increase_comment_counter(); 

가 왜이 할 수있는 일이?

감사합니다.

답변

10

동일한 content_id로 삽입되는 두 개의 설명입니다. 코멘트를 삽입하는 것만으로, 최초의 트랜잭션 (transaction)가 완료 할 때까지, 그 행을 삭제하고있는 다른 트랜잭션 (transaction)를 정지하기 위해서, 컨텐츠 행의 SHARE 락을 꺼냅니다.

그러나 트리거는 잠금을 EXCLUSIVE로 업그레이드하고 계속 진행되며 동일한 프로세스를 수행하는 동시 트랜잭션에 의해 차단 될 수 있습니다. 다음 이벤트 시퀀스를 고려하십시오.

Txn 2754      Txn 2053 
Insert Comment 
           Insert Comment 
Lock Content#935967 SHARE 
    (performed by fkey) 
           Lock Content#935967 SHARE 
           (performed by fkey) 
Trigger 
Lock Content#935967 EXCLUSIVE 
(blocks on 2053's share lock) 
           Trigger 
           Lock Content#935967 EXCLUSIVE 
           (blocks on 2754's share lock) 

소프.

즉시에 대한 독점적 인 잠금을 취한 후 주석을 삽입하십시오. 즉

SELECT 1 FROM content WHERE content.id = 935967 FOR UPDATE 
INSERT INTO comment(.....) 

또 다른 해결책은 당신이 성능에 필요한 증명할 수있는 경우를 제외하고, 완전히이 "캐시 카운트"패턴을 방지하는 것입니다. 그렇다면 콘텐츠 표가 아닌 다른 곳에 캐시 된 수를 유지하는 것이 좋습니다. 카운터 전용 테이블. 그러면 주석이 추가 될 때마다 컨텐츠 테이블에 대한 업데이트 트래픽이 줄어 듭니다. 또는 카운트를 다시 선택하고 응용 프로그램에서 memcached를 사용하십시오. 이 캐시 된 개수를 저장할 때마다 초크 포인트가 될 수 있으므로 안전하게 업데이트해야한다는 사실을 알 수 없습니다.

+0

감사합니다. 훌륭한 일! :) – lestat

+0

교착 상태 감지를위한 파이썬 테스트를 작성하고 업데이트를 선택하면 도움이되지 않는 것 같습니다 : ( – lestat

+0

'업데이트 선택'을 수행하고 동일한 트랜잭션에 주석을 삽입하고 있습니까? 실제로 다른 프로세스를 차단하고 있습니다. 'select for update' 또는 삽입물에 모두 들어가야합니까? – araqnid