sql >> Databasteknik >  >> RDS >> PostgreSQL

SKAPA SCHEMA OM INTE FINNS ger upphov till dubblettnyckelfel

Detta är lite av en vårta i implementeringen av IF NOT EXISTS för tabeller och scheman. I grund och botten är de ett upprört försök, och PostgreSQL hanterar inte tävlingsförhållandena rent. Det är säkert, men fult.

Om schemat skapas samtidigt i en annan session men ännu inte har bestämts, både existerar och existerar det inte, beroende på vem du är och hur du ser ut. Det är inte möjligt för andra transaktioner att "se" det nya schemat i systemkatalogerna eftersom det är oengagerat, så det är inmatning i pg_namespace är inte synlig för andra transaktioner. Så CREATE SCHEMA / CREATE TABLE försöker skapa det eftersom objektet inte existerar.

Men det infogar en rad i en tabell med en unik begränsning. Unika begränsningar måste kunna se obundna rader för att fungera. Så infogningen blockerar (stoppar) tills den första transaktionen som gjorde CREATE antingen begår eller rullar tillbaka. Om den begår avbryts den andra transaktionen, eftersom den försökte infoga en rad som bryter mot en unik begränsning. CREATE SCHEMA är inte smart nog att fånga det här fallet och försöka igen.

För att korrekt fixa detta skulle PostgreSQL förmodligen behöva predikatlåsning, där det skulle kunna låsa potentialen för en rad . Detta kan läggas till som en del av det pågående arbetet med att implementera UPSERT .

För just dessa kommandon skulle PostgreSQL förmodligen kunna göra en smutsig läsning av systemkatalogerna, där den kan se oengagerade ändringar. Sedan kan den vänta på att den oengagerade transaktionen genomförs eller återgå, göra om den smutsiga läsningen för att se om någon annan väntar och försöka igen. Men det här skulle ha ett rastillstånd där någon annan kan skapa schemat mellan när du gör läsningen för att leta efter det och när du försöker skapa det.

IF NOT EXISTS varianter skulle behöva:

  • Kontrollera om schemat finns; om det gör det, avsluta utan att göra något.
  • Försök att skapa tabellen
  • Om skapandet misslyckas på grund av ett unikt begränsningsfel, försök igen i början
  • Om tabellskapandet lyckas, avsluta

Så vitt jag vet har ingen implementerat det, eller så har de försökt och det accepterades inte. Det skulle finnas möjliga problem med brännhastighet för transaktions-ID, etc, med detta tillvägagångssätt.

Jag tror att det här är en slags bugg, men det är en "ja, vi vet" typ av bugg, inte en "vi fixar det här" typ av bugg. Skriv gärna till pgsql-bugs om det; dokumentationen bör åtminstone nämna denna varning om IF NOT EXISTS .

Jag rekommenderar inte att du gör DDL samtidigt som det.



  1. Unik nyckel med NULL

  2. Hur man gör en xml-fil från php och mysql

  3. Det går inte att infoga batch i Oracle DB med MyBatis

  4. Hur man ökar filstorleken för en datafil i SQL Server (T-SQL)