À partir de Isolement des transactions page :
Un EXPLAIN
sur ce SELECT
peut vous dire quel est le plan de requête pris, mais si la table est petite (ou vide !), PostgreSQL choisira presque certainement une analyse séquentielle au lieu de référencer l'index. Cela entraînera un verrou de prédicat sur l'ensemble de la table, provoquant un échec de sérialisation chaque fois qu'une autre transaction fait quoi que ce soit sur la table.
Sur mon système :
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)
Vous pouvez essayer d'ajouter un index et le forcer à l'utiliser :
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)
Cependant, ce n'est pas la bonne solution. Revenons un peu en arrière.
Serializable est destiné à garantir que les transactions auront exactement le même effet que si elles étaient exécutées les unes après les autres, malgré le fait que vous exécutiez ces transactions simultanément. PostgreSQL n'a pas de ressources infinies, donc s'il est vrai qu'il place des verrous de prédicat sur les données auxquelles votre requête accède réellement, les "données" peuvent signifier plus que les "lignes renvoyées".
PostgreSQL choisit de signaler les échecs de sérialisation lorsqu'il pense qu'il pourrait y avoir un problème, et non lorsqu'il est certain. (D'où la façon dont il généralise les verrous de ligne aux verrous de page.) Ce choix de conception provoque des faux positifs, comme celui de votre exemple. Les faux positifs sont loin d'être idéaux, cependant, cela n'affecte pas l'exactitude de la sémantique d'isolement.
Le message d'erreur est :
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.
Cet indice est essentiel. Votre application doit détecter les échecs de sérialisation et réessayer toute l'opération . Ceci est vrai chaque fois que SERIALIZABLE
est en jeu - il garantit l'exactitude de la série malgré la concurrence, mais il ne peut pas le faire sans l'aide de votre application. En d'autres termes, si vous effectuez réellement des modifications simultanées, la seule façon pour PostgreSQL de satisfaire aux exigences d'isolation est de demander à votre application de se sérialiser. Ainsi :