sql >> Databáze >  >> RDS >> PostgreSQL

CREATE SCHEMA IF NOT EXISTS vyvolá chybu duplicitního klíče

To je trochu problém v implementaci IF NOT EXISTS pro tabulky a schémata. V zásadě jde o rozhořčený pokus a PostgreSQL nezvládá podmínky závodu čistě. Je to bezpečné, ale ošklivé.

Pokud se schéma vytváří souběžně v jiné relaci, ale ještě není potvrzeno, pak existuje i neexistuje v závislosti na tom, kdo jste a jak vypadáte. Jiné transakce nemohou „vidět“ nové schéma v systémových katalozích, protože je nepotvrzené, takže je to záznam v pg_namespace není viditelný pro jiné transakce. Takže CREATE SCHEMA / CREATE TABLE pokusí se jej vytvořit, protože, pokud jde o něj, objekt neexistuje.

Tím se však do tabulky vloží řádek s jedinečným omezením. Aby fungovala jedinečná omezení, musí mít možnost vidět nepotvrzené řádky. Vložení se tedy zablokuje (zastaví) až do první transakce, která provedla CREATE buď potvrdí, nebo vrátí zpět. Pokud se potvrdí, druhá transakce se přeruší, protože se pokusila vložit řádek, který porušuje jedinečné omezení. CREATE SCHEMA není dost chytrý, aby zachytil tento případ a zkusil to znovu.

K řádné opravě tohoto PostgreSQL by pravděpodobně bylo potřeba predikátové zamykání, kde by mohl uzamknout potenciál pro řádek . To může být přidáno jako součást aktuální práce na implementaci UPSERT .

Pro tyto konkrétní příkazy by PostgreSQL pravděpodobně mohl provést nečisté čtení systémových katalogů, kde může vidět neprovedené změny. Pak by mohl počkat, až se nepotvrzená transakce potvrdí nebo vrátí zpět, znovu provést nečisté čtení, aby zjistil, zda nečeká někdo jiný, a zkusit to znovu. To by však mělo spornou podmínku, kdy by někdo jiný mohl vytvořit schéma mezi okamžikem, kdy provedete čtení, abyste jej zkontrolovali, a pokusem o jeho vytvoření.

Takže IF NOT EXISTS varianty by musely:

  • Zkontrolujte, zda schéma existuje; pokud ano, dokončete, aniž byste cokoli dělali.
  • Pokuste se vytvořit tabulku
  • Pokud se vytvoření nezdaří kvůli jedinečné chybě omezení, zkuste to znovu na začátku
  • Pokud se vytvoření tabulky podaří, dokončete

Pokud vím, nikdo to neimplementoval, nebo to zkusil a nebylo to přijato. S tímto přístupem by mohly nastat problémy s rychlostí vypalování ID transakce atd.

Myslím, že je to svého druhu chyba, ale je to chyba typu „jo, my víme“, nikoli chyba typu „hned to opravíme“. Neváhejte a napište o tom do pgsql-bugs; přinejmenším by dokumentace měla zmiňovat toto upozornění ohledně IF NOT EXISTS .

Nedoporučuji dělat DDL takto souběžně.



  1. Postgresql - zálohování databáze a obnova u jiného vlastníka?

  2. Nativní dotaz operátora JPA a JSON

  3. Jak používat výpisy připravené s CHOP s doložkou IN?

  4. Jak mohu použít CREATE OR REPLACE?