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

Bloqueo de predicados en PostgreSQL 9.2.1 con aislamiento serializable

Del Aislamiento de transacciones página:

Un EXPLAIN en eso SELECT puede decirle cuál es el plan de consulta que se está tomando, pero si la tabla es pequeña (¡o está vacía!), es casi seguro que PostgreSQL elegirá un escaneo secuencial en lugar de hacer referencia al índice. Esto provocará un bloqueo de predicado en toda la tabla, provocando un error de serialización cada vez que otra transacción haga algo en la tabla.

En mi sistema:

isolation=# EXPLAIN SELECT * from mydevice where cid = 1;
                        QUERY PLAN                        
----------------------------------------------------------
 Seq Scan on mydevice  (cost=0.00..23.38 rows=5 width=46)
   Filter: (cid = 1)
(2 rows)

Podría intentar agregar un índice y obligarlo a usar eso:

isolation=# CREATE INDEX mydevice_cid_key ON mydevice (cid);
CREATE INDEX
isolation=# SET enable_seqscan = off;
SET
isolation=# EXPLAIN SELECT * from mydevice where cid = 1;
                                    QUERY PLAN                                    
----------------------------------------------------------------------------------
 Index Scan using mydevice_cid_key on mydevice  (cost=0.00..8.27 rows=1 width=46)
   Index Cond: (cid = 1)
(2 rows)

Sin embargo, esta no es la solución correcta. Retrocedamos un poco.

Serializable está destinado a garantizar que las transacciones tendrán exactamente el mismo efecto que si se ejecutaran una tras otra, a pesar de que en realidad estás ejecutando estas transacciones al mismo tiempo. PostgreSQL no tiene recursos infinitos, por lo que si bien es cierto que coloca bloqueos de predicado en los datos a los que realmente accede su consulta, "datos" puede significar más que "filas devueltas".

PostgreSQL elige marcar las fallas de serialización cuando cree que podría haber un problema, no cuando es seguro. (De ahí la forma en que generaliza los bloqueos de fila a los bloqueos de página). Esta elección de diseño provoca falsos positivos, como el de su ejemplo. Los falsos positivos son menos que ideales, sin embargo, no afectan la corrección de la semántica de aislamiento.

El mensaje de error es:

ERROR:  could not serialize access due to read/write dependencies among transactions
DETAIL:  Reason code: Canceled on identification as a pivot, during commit attempt.
HINT:  The transaction might succeed if retried.

Esa pista es clave. Su aplicación necesita detectar fallas de serialización y volver a intentar toda la operación . Esto es cierto siempre que SERIALIZABLE está en juego:garantiza la corrección serial a pesar de la concurrencia, pero no puede hacerlo sin la ayuda de su aplicación. Dicho de otra manera, si realmente está realizando modificaciones simultáneas, la única forma en que PostgreSQL puede satisfacer los requisitos de aislamiento es pedirle a su aplicación que se serialice. Así: