sql >> Database teknologi >  >> RDS >> PostgreSQL

CREATE SCHEMA IF NOT EXISTS rejser dubletnøglefejl

Dette er lidt af en vorte i implementeringen af ​​IF NOT EXISTS til tabeller og skemaer. Dybest set er de et oprørsforsøg, og PostgreSQL håndterer ikke løbsforholdene rent. Det er sikkert, men grimt.

Hvis skemaet bliver oprettet samtidigt i en anden session, men endnu ikke er committet, så både eksisterer det og eksisterer ikke, afhængigt af hvem du er, og hvordan du ser ud. Det er ikke muligt for andre transaktioner at "se" det nye skema i systemkatalogerne, fordi det er uforpligtet, så det er indtastning i pg_namespace er ikke synlig for andre transaktioner. Så CREATE SCHEMA / CREATE TABLE forsøger at skabe det, fordi objektet, hvad det angår, ikke eksisterer.

Det indsætter dog en række i en tabel med en unik begrænsning. Unikke begrænsninger skal kunne se ikke-forpligtede rækker for at fungere. Så indsættelsesblokkene (stopper) indtil den første transaktion, der udførte CREATE enten forpligter eller ruller tilbage. Hvis den forpligter sig, afbrydes den anden transaktion, fordi den forsøgte at indsætte en række, der overtræder en unik begrænsning. CREATE SCHEMA er ikke smart nok til at fange denne sag og prøve igen.

For at rette dette korrekt ville PostgreSQL sandsynligvis kræve prædikatlåsning, hvor det kunne låse potentialet for en række . Dette kan blive tilføjet som en del af det igangværende arbejde med at implementere UPSERT .

For disse særlige kommandoer kunne PostgreSQL sandsynligvis lave en dirty read af systemkatalogerne, hvor den kan se ikke-forpligtede ændringer. Derefter kunne den vente på, at den ikke-forpligtede transaktion forpligtes eller rulle tilbage, gentage den beskidte læsning for at se, om en anden venter, og prøve igen. Men dette ville have en race-tilstand, hvor en anden kunne oprette skemaet mellem, hvornår du læser for at tjekke det, og når du forsøger at oprette det.

IF NOT EXISTS varianter skal:

  • Tjek for at se, om skemaet eksisterer; hvis det gør, skal du afslutte uden at gøre noget.
  • Forsøg på at oprette tabellen
  • Hvis oprettelsen mislykkes på grund af en unik begrænsningsfejl, skal du prøve igen i starten
  • Hvis oprettelsen af ​​tabellen lykkes, skal du afslutte

Så vidt jeg ved, har ingen implementeret det, eller de forsøgte, og det blev ikke accepteret. Der ville være mulige problemer med transaktions-id's brændhastighed osv. med denne tilgang.

Jeg tror, ​​at dette er en slags fejl, men det er en "ja, vi ved det" slags fejl, ikke en "vi skal nok rette op på den" slags fejl. Du er velkommen til at skrive til pgsql-bugs om det; i det mindste bør dokumentationen nævne denne advarsel om IF NOT EXISTS .

Jeg anbefaler ikke at gøre DDL på den måde samtidigt.



  1. Gennemsnit af data for hvert 5. minut på de givne tidspunkter

  2. SQL-forespørgsel for at få summen af ​​alle kolonneværdier i den sidste række af et resultatsæt sammen med rækkesum (grupper efter)

  3. Oracle ORA-00933:SQL-kommando blev ikke afsluttet korrekt?

  4. MySQL Select og IF() Statement