Estou executando consultas simultâneas do Postgres como esta:
UPDATE foo SET bar = bar + 1 WHERE baz = 1234
Cada consulta afeta o número fixo de K linhas e, não consigo encontrar uma maneira de impor a ordem na qual as linhas são atualizadas, acabo com impasses. Atualmente, eu corrijo o problema aplicando a ordem manualmente, mas isso significa que tenho que executar muito mais consultas do que normalmente faria, além de aumentar a complexidade da pesquisa de O (log N + K) para O (K log N).
Existe uma maneira de melhorar o desempenho sem acabar vulnerável a conflitos? Eu suspeito que a substituição do (baz)
índice pelo (baz, id)
índice possa funcionar, desde que o Postgres atualize as linhas na mesma ordem em que foram verificadas. É uma abordagem que vale a pena seguir?
postgresql
locking
deadlock
update
Alexei Averchenko
fonte
fonte
CREATE TABLE
código.Respostas:
Não existe
ORDER BY
umSQL UPDATE
comando. O Postgres atualiza as linhas em ordem arbitrária:Para evitar conflitos com certeza absoluta, você pode executar suas instruções em isolamento de transação serializável . Mas isso é mais caro e você precisa se preparar para repetir comandos na falha de serialização.
Seu melhor curso de ação é provavelmente bloquear explicitamente
SELECT ... ORDER BY ... FOR UPDATE
em uma subconsulta ou autônomoSELECT
em uma transação - no nível de isolamento "leitura confirmada" padrão. Citando Tom Lane no pgsql-general :Isso deve fazer o trabalho:
Um índice de várias colunas ativado
(baz, bar)
pode ser perfeito para desempenho. Mas comobar
é obviamente atualizado muito , um índice de coluna única(baz)
pode ser ainda melhor. Depende de alguns fatores. Quantas linhas porbaz
? As atualizações HOT são possíveis sem o índice de várias colunas? ...Se
baz
for atualizado simultaneamente, ainda há uma chance improvável de ocorrência de conflitos (por documentação) :Além disso, se você tiver uma restrição exclusiva
bar
, considere umaDEFERRABLE
restrição para evitar violações exclusivas dentro do mesmo comando. Resposta relacionada:fonte
id
ou outra coluna única em vez debar
, não deve haver uma caixa de canto ou uma ocorrência de desempenho, certo?