sql >> Databasteknik >  >> RDS >> PostgreSQL

Predikatlåsning i PostgreSQL 9.2.1 med serialiserbar isolering

Från Transaktionsisolering sida:

En EXPLAIN på den SELECT kan berätta vilken frågeplan som tas, men om tabellen är liten (eller tom!), kommer PostgreSQL nästan säkert att välja en sekventiell skanning istället för att referera till indexet. Detta kommer att orsaka ett predikatlås på hela bordet, vilket orsakar serialiseringsfel när en annan transaktion gör något med bordet.

På mitt system:

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)

Du kan försöka lägga till ett index och tvinga det att använda det:

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)

Detta är dock inte den korrekta lösningen. Låt oss backa lite.

Serializable är tänkt att garantera att transaktioner kommer att ha exakt samma effekt som om de kördes en efter en, trots att du faktiskt kör dessa transaktioner samtidigt. PostgreSQL har inte oändliga resurser, så även om det är sant att det sätter predikatlås på data som din fråga faktiskt kommer åt, kan "data" betyda mer än "rader som returneras".

PostgreSQL väljer att flagga serialiseringsfel när den tror att det kan finnas ett problem, inte när det är säkert. (Därav hur det generaliserar radlås till sidlås.) Detta designval orsakar falska positiva resultat, som det i ditt exempel. Falska positiva är mindre än idealiska, men det påverkar inte korrektheten av isoleringssemantiken.

Felmeddelandet är:

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.

Det tipset är nyckeln. Din applikation måste fånga serialiseringsfel och försöka hela operationen igen . Detta gäller när SERIALIZABLE är i spel -- det garanterar seriell korrekthet trots samtidighet, men det kan inte göra det utan hjälp av din applikation. Med andra ord, om du faktiskt gör samtidiga ändringar, är det enda sättet som PostgreSQL kan uppfylla isoleringskraven att be din applikation att serialisera sig själv. Alltså:



  1. Använder en villkorlig UPDATE-sats i SQL

  2. Det går inte att ansluta till Postgres DB på grund av autentiseringstypen 10 stöds inte

  3. INFOGA flera poster med ruby ​​on rails aktiva post

  4. Länka samman tabeller mellan två modeller i Cakephp