No PostgreSQL, as linhas serão bloqueadas à medida que forem atualizadas - na verdade, a maneira como isso realmente funciona é que cada tupla (versão de uma linha) tem um campo de sistema chamado
xmin
para indicar qual transação tornou aquela tupla atual (por inserção ou atualização) e um campo de sistema chamado xmax
para indicar qual transação expirou essa tupla (por atualização ou exclusão). Quando você acessa os dados, ele verifica cada tupla para determinar se ela está visível para sua transação, verificando seu "instantâneo" ativo em relação a esses valores. Se você estiver executando um UPDATE e uma tupla que corresponda às suas condições de pesquisa tiver um xmin que a tornaria visível para seu instantâneo e um xmax de uma transação ativa, ela bloqueará, aguardando a conclusão dessa transação. Se a transação que primeiro atualizou a tupla for revertida, sua transação será ativada e processará a linha; se a primeira transação for confirmada, sua transação será ativada e agirá dependendo do nível de isolamento da transação atual.
Obviamente, um deadlock é o resultado disso acontecer com linhas em ordem diferente. Não há bloqueio em nível de linha na RAM que possa ser obtido para todas as linhas ao mesmo tempo, mas se as linhas forem atualizadas na mesma ordem, você não poderá ter o bloqueio circular. Infelizmente, o
IN(1, 2)
sugerido sintaxe não garante isso. Sessões diferentes podem ter diferentes fatores de custo ativos, uma tarefa "analisar" em segundo plano pode alterar as estatísticas da tabela entre a geração de um plano e a outra, ou pode estar usando um seqscan e ser afetada pela otimização do PostgreSQL que causa um novo seqscan para juntar-se a um já em andamento e "circular" para reduzir a E/S do disco. Se você fizer as atualizações uma de cada vez na mesma ordem, no código do aplicativo ou usando um cursor, você terá apenas bloqueios simples, não impasses. Em geral, porém, os bancos de dados relacionais são propensos a falhas de serialização, e é melhor acessá-los por meio de uma estrutura que os reconhecerá com base no SQLSTATE e tentará novamente toda a transação desde o início. No PostgreSQL uma falha de serialização sempre terá um SQLSTATE de 40001 ou 40P01.
http://www.postgresql.org/docs/current/interactive/mvcc-intro.html