TL;DR:Detekce konfliktů serializace se v Pg 9.1 dramaticky zlepšila, proto upgradujte.
Je složité z vašeho popisu zjistit, co je skutečný SQL a proč očekáváte vrácení zpět. Vypadá to, že jste vážně špatně pochopili serializovatelnou izolaci, možná si myslíte, že dokonale testuje všechny predikáty, což nedělá, zvláště ne v Pg 8.4.
SERIALIZABLE
nezaručuje dokonale, že se transakce provádějí, jako by byly spuštěny v sérii – protože by to bylo z hlediska výkonu neúnosně drahé, pokud by to bylo vůbec možné. Poskytuje pouze omezenou kontrolu. Co přesně se kontroluje a jak se liší databáze od databáze a verze od verze, takže si musíte přečíst dokumenty pro svou verzi databáze.
Anomálie jsou možné, když se dvě transakce provádějí v SERIALIZABLE
způsobí jiný výsledek, než kdyby byly tyto transakce skutečně provedeny v sérii.
Chcete-li se dozvědět více, přečtěte si dokumentaci o izolaci transakcí v Pg. Všimněte si, že SERIALIZABLE
dramaticky změnilo chování v Pg 9.1, takže si přečtěte verzi příručky odpovídající vaší verzi Pg. Zde je verze 8.4
. Zejména si přečtěte 13.2.2.1. Serializovatelná izolace versus skutečná serializovatelnost
. Nyní to porovnejte s výrazně vylepšenou podporou serializace založenou na predikátovém uzamčení popsanou v Dokumenty na str. 9.1
.
Vypadá to, že se pokoušíte provést logiku, něco jako tento pseudokód:
count = query("SELECT count(*) FROM the_table");
if (count < threshold):
query("INSERT INTO the_table (...) VALUES (...)");
Pokud ano, nebude to fungovat v Pg 8.4 při souběžném spuštění - je to v podstatě stejné jako příklad anomálie použitý ve výše uvedené dokumentaci. Překvapivě to skutečně funguje na Pg 9.1; Nečekal jsem, že ani predikátové zamykání 9.1 zachytí použití agregátů.
Píšete, že:
ale 8.4 nezjistí, že tyto dvě transakce jsou na sobě závislé, což můžete triviálně dokázat pomocí dvou psql
sezení, abyste to otestovali. To bude fungovat pouze se skutečnou serializovatelností zavedenou v 9.1 - a upřímně řečeno, byl jsem překvapen, že to funguje v 9.1.
Pokud chcete udělat něco jako vynucení maximálního počtu řádků v Pg 8.4, musíte LOCK
stůl
abyste zabránili souběžnému INSERT
s, provedete zamykání buď ručně, nebo pomocí funkce spouštění . Pokud to uděláte ve spouštěči, bude ze své podstaty vyžadovat povýšení zámku, a proto se často zablokuje, ale svou práci úspěšně zvládne. Je lepší to udělat v aplikaci, kde můžete vydat LOCK TABLE my_table IN EXCLUSIVE MODE
před získáním dokonce SELECT
od stolu, takže již má nejvyšší režim uzamčení, který bude na stole potřebovat, a proto by neměl potřebovat propagaci zámku náchylného k uváznutí. EXCLUSIVE
režim uzamčení je vhodný, protože umožňuje SELECT
s ale nic jiného.
Zde je návod, jak to otestovat ve dvou psql relacích:
SESSION 1 SESSION 2
create table ser_test( x text );
BEGIN TRANSACTION
ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION
ISOLATION LEVEL SERIALIZABLE;
SELECT count(*) FROM ser_test ;
SELECT count(*) FROM ser_test ;
INSERT INTO ser_test(x) VALUES ('bob');
INSERT INTO ser_test(x) VALUES ('bob');
COMMIT;
COMMIT;
Při spuštění na Pg 9.1 je st commits succeeds then the second
COMMIT` se nezdaří s:
regress=# COMMIT;
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.
ale při spuštění na 8.4 jsou obě revize úspěšné, protože 8.4 nemělo v 9.1 přidaný veškerý predikátový zamykací kód pro serializaci.