sql >> Database >  >> RDS >> PostgreSQL

CREER SCHEMA INDIEN NIET BESTAAT leidt tot dubbele sleutelfout

Dit is een beetje een wrat in de implementatie van IF NOT EXISTS voor tabellen en schema's. Kortom, ze zijn een poging tot ophef, en PostgreSQL gaat niet netjes om met de race-omstandigheden. Het is veilig, maar lelijk.

Als het schema gelijktijdig in een andere sessie wordt gemaakt maar nog niet is vastgelegd, dan bestaat het wel en niet, afhankelijk van wie je bent en hoe je eruitziet. Het is niet mogelijk voor andere transacties om het nieuwe schema in de systeemcatalogi te "zien", omdat het niet is vastgelegd, dus het is invoer in pg_namespace is niet zichtbaar voor andere transacties. Dus CREATE SCHEMA / CREATE TABLE probeert het te creëren omdat het object wat hem betreft niet bestaat.

Dat voegt echter een rij in een tabel in met een unieke beperking. Unieke beperkingen moeten niet-vastgelegde rijen kunnen zien om te kunnen functioneren. Dus het invoegen blokkeert (stopt) tot de eerste transactie die de CREATE . deed ofwel vastlegt of terugdraait. Als het een commit doet, wordt de tweede transactie afgebroken, omdat het probeerde een rij in te voegen die een unieke beperking schendt. CREATE SCHEMA is niet slim genoeg om deze zaak op te pakken en het opnieuw te proberen.

Om dit op de juiste manier op te lossen, zou PostgreSQL waarschijnlijk predikaatvergrendeling nodig hebben, waar het het potentieel voor een rij zou kunnen vergrendelen . Dit kan worden toegevoegd als onderdeel van het huidige werk voor de implementatie van UPSERT .

Voor deze specifieke commando's zou PostgreSQL waarschijnlijk een vuile lezing kunnen doen van de systeemcatalogi, waar het niet-vastgelegde wijzigingen kan zien. Dan kan het wachten tot de niet-vastgelegde transactie is vastgelegd of teruggedraaid, de dirty read opnieuw doen om te zien of iemand anders wacht en het opnieuw proberen. Maar dit zou een race-conditie hebben waarbij iemand anders het schema zou kunnen maken tussen het moment waarop je het leest om het te controleren en wanneer je het probeert te maken.

Dus de IF NOT EXISTS varianten zouden moeten:

  • Controleer of het schema bestaat; als dat zo is, maak dan af zonder iets te doen.
  • Poging om de tabel te maken
  • Als het maken mislukt vanwege een unieke beperkingsfout, probeer het dan opnieuw aan het begin
  • Als het maken van de tabel lukt, voltooi dan

Voor zover ik weet heeft niemand dat geïmplementeerd, of ze hebben het geprobeerd en het werd niet geaccepteerd. Met deze aanpak zouden er mogelijke problemen zijn met de brandsnelheid van transactie-ID's, enz.

Ik denk dat dit een soort bug is, maar het is een "ja, we weten" soort bug, niet een "we komen er zo aan om die te repareren" soort bug. Voel je vrij om erover te posten op pgsql-bugs; op zijn minst zou de documentatie dit voorbehoud moeten vermelden over IF NOT EXISTS .

Ik raad niet aan om DDL op die manier tegelijkertijd te doen.



  1. Hoe MySQL-transacties correct te gebruiken

  2. 3 vervelende I/O-statistieken die de prestaties van SQL-query's vertragen

  3. Waarom is mijn zoekopdracht met meerdere kolommen aanzienlijk langzamer dan de overeenkomstige zoekopdrachten met één kolom, zelfs met een index met meerdere kolommen?

  4. SIGN() Functie in Oracle