PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Bloqueio de predicado no PostgreSQL 9.2.1 com isolamento serializável


Do Isolamento de transação página:

Uma EXPLAIN nesse SELECT pode dizer qual plano de consulta está sendo feito, mas se a tabela for pequena (ou vazia!), o PostgreSQL quase certamente escolherá uma varredura sequencial em vez de referenciar o índice. Isso causará um bloqueio de predicado em toda a tabela, causando falha de serialização sempre que outra transação fizer algo na tabela.

No meu sistema:
isolation=# EXPLAIN SELECT * from mydevice where cid = 1;
                        QUERY PLAN                        
----------------------------------------------------------
 Seq Scan on mydevice  (cost=0.00..23.38 rows=5 width=46)
   Filter: (cid = 1)
(2 rows)

Você pode tentar adicionar um índice e forçá-lo a usar isso:
isolation=# CREATE INDEX mydevice_cid_key ON mydevice (cid);
CREATE INDEX
isolation=# SET enable_seqscan = off;
SET
isolation=# EXPLAIN SELECT * from mydevice where cid = 1;
                                    QUERY PLAN                                    
----------------------------------------------------------------------------------
 Index Scan using mydevice_cid_key on mydevice  (cost=0.00..8.27 rows=1 width=46)
   Index Cond: (cid = 1)
(2 rows)

No entanto, esta não é a solução correta. Vamos recuar um pouco.

Serializable destina-se a garantir que as transações tenham exatamente o mesmo efeito como se fossem executadas uma após a outra, apesar do fato de você estar executando essas transações simultaneamente. O PostgreSQL não possui recursos infinitos, portanto, embora seja verdade que ele coloca bloqueios de predicado nos dados que sua consulta realmente acessa, "dados" pode significar mais do que "linhas retornadas".

O PostgreSQL escolhe sinalizar falhas de serialização quando acha que pode haver um problema, não quando é certo. (Daí como ele generaliza bloqueios de linha para bloqueios de página.) Essa escolha de design causa falsos positivos, como o do seu exemplo. Os falsos positivos são menos do que ideais, no entanto, não afetam a correção da semântica de isolamento.

A mensagem de erro é:
ERROR:  could not serialize access due to read/write dependencies among transactions
DETAIL:  Reason code: Canceled on identification as a pivot, during commit attempt.
HINT:  The transaction might succeed if retried.

Essa dica é fundamental. Seu aplicativo precisa detectar falhas de serialização e repetir toda a operação . Isso é verdade sempre que SERIALIZABLE está em jogo -- ele garante a correção serial apesar da simultaneidade, mas não pode fazer isso sem a ajuda do seu aplicativo. Dito de outra forma, se você está realmente fazendo modificações simultâneas, a única maneira de o PostgreSQL satisfazer os requisitos de isolamento é pedir que seu aplicativo se serialize. Desta forma: