Warum verursacht eine Einfügung, die nach dem Primärschlüssel gruppiert, einen Fehler bei der Primärschlüsseleinschränkungsverletzung?

8

Ich habe eine insert-Anweisung, die einen primären Schlüsselfehler verursacht, aber ich sehe nicht, wie ich möglicherweise doppelte Schlüsselwerte einfügen könnte.

Zuerst erstelle ich eine temporäre Tabelle mit einem Primärschlüssel.

%Vor%

Dann ziehe ich Preise aus der Prices-Tabelle, gruppiert nach idIsbn, welches der Primärschlüssel in der Temp-Tabelle ist.

%Vor%

Ich verstehe, dass die Gruppierung nach idIsbn es per Definition einzigartig macht. Die idIsbn in der Preistabelle ist: [idIsbn] [int] NOT NULL .

Aber ab und zu wenn ich diese Abfrage ausführe, bekomme ich diesen Fehler:

%Vor%

HINWEIS: Ich habe viele Fragen zum Timing. Ich werde diese Aussage auswählen, F5 drücken, und kein Fehler wird auftreten. Dann werde ich es wieder tun, und es wird scheitern, dann werde ich es immer wieder ausführen und es wird ein paar Mal erfolgreich sein, bevor es wieder fehlschlägt. Ich denke, was ich sagen will, ist, dass ich kein Muster dafür finden kann, wann es erfolgreich sein wird und wann nicht.

Wie kann ich doppelte Zeilen einfügen, wenn (A) ich die Tabelle gerade neu erstellt habe, bevor ich sie eingefügt habe und (B) ich mich nach der Spalte gruppiere, die als Primärschlüssel dient?

Im Moment löse ich das Problem mit IGNORE_DUP_KEY = ON , aber ich möchte wirklich die Ursache des Problems wissen.

Hier ist, was ich tatsächlich in meinem SSMS-Fenster sehe. Es gibt nichts mehr und nicht weniger:

@@ Version ist:

%Vor%

Ausführungsplan:

Hier ist ein Beispiel dafür, wie es aussieht, wenn es gut läuft. Hier verwende ich READ COMMITTED, aber es spielt keine Rolle, b / c Ich bekomme den Fehler, egal ob ich es Committed oder Committed gelesen habe.

Hier ist ein weiteres Beispiel, dass es fehlschlägt, diesmal mit READ COMMITTED.

Auch:

  • Ich bekomme den gleichen Fehler, wenn ich eine temporäre Tabelle oder eine persistente Tabelle.
  • Wenn ich am Ende der Einfügung option (maxdop 1) hinzufüge, scheint es jedes Mal zu scheitern, obwohl ich nicht sicher sein kann, ob es b / c ist. Ich kann es nicht für die Unendlichkeit laufen lassen. Aber es scheint so zu sein.

Hier ist die Definition der Preistabelle. Tabelle hat 25M Zeilen. 108.529 Updates in der letzten Stunde.

%Vor%

Und die zwei nicht gruppierten Indizes:

%Vor%     
Trevor 30.03.2016, 19:53
quelle

1 Antwort

6

Sie haben Ihre Tabellenstruktur nicht angegeben.

Dies ist ein Repro mit einigen angenommenen Details, der das Problem beim Lesen verursacht (NB: Jetzt haben Sie die Definition geliefert, die ich in Ihrem Fall sehe) Aktualisierungen der priceChangedDate -Spalte verschieben Zeilen im IX_Price_idMarketplace_priceChangedDate_INC_idIsbn_lowestPrice -Index wenn das der gesuchte ist)

Verbindung 1 (Tabellen einrichten)

%Vor%

Verbindung 2

Gleichzeitige DataModifications, die eine Zeile vom Anfang des gesuchten Bereichs (3100,1) bis zum Ende (3100,2001) und wieder zurück verschieben.

%Vor%

Verbindung 3 (Führen Sie die Einfügung in eine temporäre Tabelle mit einer eindeutigen Einschränkung durch)

%Vor%

Der Plan hat kein Aggregat, da es eine eindeutige Einschränkung für idIsbn gibt (eine eindeutige Einschränkung für idIsbn, idMarketplace würde auch funktionieren), daher kann die Gruppe nach optimiert werden, da es keine doppelten Werte gibt.

Aber bei Read-Committed-Isolationsstufen werden freigegebene Zeilensperren freigegeben, sobald die Zeile gelesen wird. Es ist also möglich, dass eine Reihe die Plätze verschiebt und ein zweites Mal mit derselben Suche oder demselben Scan gelesen wird.

Der Index ix enthält SomeKey nicht explizit als sekundäre Schlüsselspalte, aber da er nicht eindeutig deklariert wird, fügt SQL Server automatisch den Clustering-Schlüssel hinter den Szenen ein. Daher können durch das Aktualisieren dieses Spaltenwerts Zeilen darin verschoben werden .

    
Martin Smith 30.03.2016, 21:54
quelle

Tags und Links