Estoy ejecutando consultas concurrentes de Postgres como esta:
UPDATE foo SET bar = bar + 1 WHERE baz = 1234
Cada consulta afecta el número fijo K de filas, y no puedo encontrar una manera de imponer el orden en que se actualizan las filas, termino con puntos muertos. Actualmente soluciono el problema aplicando el orden a mano, pero esto significa que tengo que ejecutar muchas más consultas de las que normalmente haría al tiempo que aumentaba la complejidad de búsqueda de O (log N + K) a O (K log N).
¿Hay alguna manera de mejorar el rendimiento sin llegar a ser vulnerable a puntos muertos? Sospecho que reemplazar el (baz)
índice con el (baz, id)
índice podría funcionar siempre que Postgres actualice las filas en el mismo orden en que las ha escaneado, ¿vale la pena seguir este enfoque?
postgresql
locking
deadlock
update
Alexei Averchenko
fuente
fuente
CREATE TABLE
código.Respuestas:
No hay
ORDER BY
en unSQL UPDATE
comando. Postgres actualiza las filas en orden arbitrario:Para evitar puntos muertos con absoluta certeza, puede ejecutar sus declaraciones en aislamiento de transacciones serializables . Pero eso es más costoso y debe prepararse para repetir comandos en caso de falla de serialización.
Su mejor curso de acción es probablemente bloquear explícitamente
SELECT ... ORDER BY ... FOR UPDATE
en una subconsulta oSELECT
en una transacción independiente, en el nivel de aislamiento predeterminado "lectura confirmada". Citando a Tom Lane en pgsql-general :Esto debería hacer el trabajo:
Un índice de varias columnas
(baz, bar)
puede ser perfecto para el rendimiento. Pero comobar
obviamente se actualiza mucho , un índice de una sola columna(baz)
podría ser aún mejor. Depende de un par de factores. ¿Cuántas filas porbaz
? ¿Son posibles las actualizaciones HOT sin el índice de varias columnas? ...Si
baz
se actualiza al mismo tiempo, todavía hay una posibilidad improbable de conflictos en el caso de la esquina (según la documentación) :Además, si debe tener una restricción única que implique
bar
, considere unaDEFERRABLE
restricción para evitar violaciones únicas dentro del mismo comando. Respuesta relacionada:fuente
id
o alguna otra columna única en lugar debar
, no debería haber un caso de esquina o un golpe de rendimiento, ¿verdad?