sql >> Base de Datos >  >> RDS >> PostgreSQL

Actualización de filas de base de datos sin bloquear la tabla en PostgreSQL 9.2

MVCC

En primer lugar, si las "operaciones normales" consisten en SELECT consultas, el modelo MVCC se encargará de ello automáticamente. UPDATE no bloquea SELECT y viceversa. SELECT solo ve los datos comprometidos (o lo que se ha hecho en la misma transacción), por lo que el resultado de la gran UPDATE permanece invisible para otras transacciones hasta que se realiza (comprometido).

Rendimiento/hinchazón

Si no tiene otros objetos que hagan referencia a esa tabla,
y no tiene operaciones de escritura simultáneas (¡que se perderían!),
y puede permitirse un bloqueo exclusivo muy corto en la mesa,
y tiene el espacio adicional en disco, por supuesto:
Puede mantener el bloqueo al mínimo creando una versión actualizada de la tabla en segundo plano. Asegúrate de que tiene todo para ser un reemplazo directo, luego suelte el original y cambie el nombre del duplicado.

CREATE TABLE tbl_new (LIKE tbl_org INCLUDING CONSTRAINTS);

INSERT INTO tbl_new 
SELECT col_a, col_b, array[col] aS col_c
FROM   tbl_org;

Estoy usando CREATE TABLE (LIKE .. INCLUDING CONSTRAINTS) , porque (citando el manual aquí):

Las restricciones no nulas siempre se copian en la nueva tabla. CHECK las restricciones solo se copiarán si INCLUDING CONSTRAINTS se especifica; otros tipos de restricciones nunca se copiarán.

Asegúrese de que la nueva mesa esté lista. Entonces:

DROP tbl_org;
ALTER TABLE tbl_new RENAME TO tbl_org;

Da como resultado una ventana de tiempo muy breve, donde la mesa se bloquea exclusivamente.

Esto es realmente sólo sobre el rendimiento. Crea una nueva tabla sin ningún tipo de hinchazón con bastante rapidez. Si tiene vistas o claves foráneas, aún puede seguir esa ruta, pero debe preparar una secuencia de comandos para descartar y volver a crear estos objetos, lo que podría crear bloqueos exclusivos adicionales.

Escrituras simultáneas

Con las operaciones de escritura concurrentes, realmente todo lo que puede hacer es dividir su actualización en partes. No puede hacer eso en una sola transacción, ya que los bloqueos solo se liberan al final de una transacción.

podrías emplear dblink , que puede iniciar transacciones independientes en otra base de datos, incluida ella misma. De esta manera podrías hacerlo todo en un solo DO instrucción o una función plpgsql con un bucle. Aquí hay una respuesta vagamente relacionada con más información sobre dblink:

  • Eliminar o crear una base de datos a partir de un procedimiento almacenado en PostgreSQL

Tu enfoque con cursores

Un cursor dentro de la función no le comprará nada . Cualquier función se incluye en una transacción automáticamente, y todos los bloqueos solo se liberan al final de la transacción. Incluso si usó CLOSE cursor (que no lo hace) solo liberaría algunos recursos, pero no suelte los bloqueos adquiridos en la mesa. Cito el manual:

CLOSE cierra el portal subyacente a un cursor abierto. Esto se puede usar para liberar recursos antes del final de la transacción, o para liberar la variable del cursor para abrirla nuevamente.

Tendría que ejecutar separado transacciones o (ab) usar dblink que lo hace por usted.