Incremento concurrente PostgreSQL de contador

9

Necesito mantener una tabla estadística para un proyecto, compuesta por una lista de elementos y su uso (piense en algo como un sitio web en el que le gustaría contar las visitas a la página). Cada vez que se instancia un elemento, necesito aumentar el uso del elemento específico.

Mi primera implementación es:

statistics(
  id      integer NOT NULL,
  name    character varying(255) NOT NULL,
  usage   integer NOT NULL DEFAULT 0,
);


UPDATE statistics 
  SET usage = usage + 1
WHERE name = '<name>';

Mis preocupaciones son sobre el rendimiento y la concurrencia. El proceso de actualización será instanciado por varias decenas (quizás 80-120) dispositivos y podría ocurrir varias veces por segundo, así que mis preguntas son:

1) ¿este método preservará la concurrencia? (es decir, si más de un dispositivo solicita la actualización "al mismo tiempo", ¿se contará cada solicitud?)

2) ¿puede sugerir una mejor manera de lograr el resultado? Espero tener carga al escribir las actualizaciones, mientras que las lecturas serían mucho más frecuentes. ¿Existe una función específica para incrementar los valores? Estoy mirando "secuencia" pero no estoy seguro si esa es la forma correcta ...

Muchas gracias de antemano por cualquier consejo

estudiante de inglés
fuente

Respuestas:

5

La segunda actualización esperaría a que se actualizara la actualización anterior en las mismas filas, pero luego verá el valor comprometido.

Suponga que dos transacciones concurrentes actualizan la misma fila con un valor inicial de 0

Transición de tiempo 1 Valor T1 Transacción 2 Valor T2
-------------------------------------------------- ------------
1 actualización ... 1 0
2 1 actualización .. "indefinido"
                                (murga) 
3 commit 1 2
4 1 commit 2
5 2 2 

"Valor T1" y "Valor T2" significa el valor que ve esa transacción.

Si desea asegurarse de detectar situaciones en las que hay cambios "incompatibles" (por ejemplo, una transacción que establece la usagecolumna en un valor específico, en lugar de simplemente incrementarla), puede colocar todas las transacciones en el nivel de aislamiento "serializable". Pero entonces deberá prepararse para el manejo de errores.

Las actualizaciones de diferentes nombres pueden ejecutarse simultáneamente sin esperas (porque se ven afectadas diferentes filas).

SELECTs nunca se bloqueará, pero solo verá los valores comprometidos.

un caballo sin nombre
fuente