MSG 666 beim Ausführen einer Einfügeabfrage für eine indizierte Tabelle mit 80 Millionen Zeilen

10

Seltsamerweise empfing meine gespeicherte Prozedur für einige Eingabedaten Nachricht 666.

Die gespeicherte Prozedur schlägt im letzten Schritt fehl, wenn versucht wird, eine Zeile in eine Tabelle mit der folgenden Struktur einzufügen:

Columns:
A_Id: PK, int
B_Id: PK, FK, int
C_Id: PK, FK, int
D_Id: PK, smallint 

Dies ist im Wesentlichen eine Tabelle, die alle referenzierten Entitäten miteinander verbindet.

Indexes:
IX_TableName_D_id - Clustered index on D_id column
PK_TableName - Unique non-clustered index on all columns (A_Id, B_Id, C_Id, D_Id)

Die Fragmentierung für beide Indizes ist gering (<25%). Die Fragmentierung von PK_TableName nimmt jedoch schnell zu, da die Anzahl der Operationen in der Tabelle sehr hoch ist.

Tischgröße:

Row count: ~80,000,000 rows

Wenn ich also versuche, eine sehr einfache Abfrage auszuführen, erhalte ich für einige D_Ids die folgende Meldung:

Meldung 666. Der maximale vom System generierte eindeutige Wert für eine doppelte Gruppe wurde für den Index mit der Partitions-ID 422223771074560 überschritten. Durch Löschen und erneutes Erstellen des Index wird dies möglicherweise behoben. Verwenden Sie andernfalls einen anderen Clustering-Schlüssel.

Abfragebeispiel:

INSERT INTO TableName
(A_Id,B_Id,C_Id,D_id)
VALUES (1,1,1,14)

Wenn ich zum Beispiel D_Id auf einige Werte setze, schlägt dies fehl, zum Beispiel '14'. Wenn ich D_ID auf andere Werte setze (1,2,3, ... 13, 15,16, ...), läuft die Abfrage einwandfrei.

Ich vermute, dass mit Indizes etwas wirklich Schlimmes los ist ... Aber ich kann dem nicht auf den Grund gehen ... :( Warum scheitert es?

Igor Malin
quelle

Antworten:

16

Das von Remus erwähnte Problem der geringen Selektivität allein reicht nicht aus, um das Problem in dieser Größentabelle zu verursachen.

Der Uniqueifier beginnt bei 1und kann bis zu gehen, 2,147,483,646bevor der Bereich tatsächlich überläuft.

Es erfordert auch das richtige Muster wiederholter Lösch- und Einfügungen, um das Problem zu erkennen.

CREATE TABLE T
(
X SMALLINT,
Y INT IDENTITY PRIMARY KEY NONCLUSTERED
)

CREATE CLUSTERED INDEX IX ON T(X)

INSERT INTO T VALUES (1),(1),(1),(2),(2)

Gibt

+---+---+-------------+
| X | Y | Uniqueifier |
+---+---+-------------+
| 1 | 1 |             |
| 1 | 2 |           1 |
| 1 | 3 |           2 |
| 2 | 4 |             |
| 2 | 5 |           1 |
+---+---+-------------+

Dann rennen

DELETE FROM T 
WHERE Y IN (2,3)

INSERT INTO T VALUES (1),(1)

Gibt

+---+---+-------------+
| X | Y | Uniqueifier |
+---+---+-------------+
| 1 | 1 |             |
| 1 | 6 |           3 |
| 1 | 7 |           4 |
| 2 | 4 |             |
| 2 | 5 |           1 |
+---+---+-------------+

In diesem Fall hat der Uniqueifier die Werte aus den gelöschten Zeilen nicht wiederverwendet.

Allerdings läuft dann

DELETE FROM T 
WHERE Y IN (6,7)
WAITFOR DELAY '00:00:10'
INSERT INTO T VALUES (1),(1)

Gibt

+---+---+-------------+
| X | Y | Uniqueifier |
+---+---+-------------+
| 1 | 1 |             |
| 1 | 8 |           1 |
| 1 | 9 |           2 |
| 2 | 4 |             |
| 2 | 5 |           1 |
+---+---+-------------+

Zeigen, dass die Hochwassermarke nach dem Löschen des Duplikats mit dem höchsten eindeutigen Wert zurückgesetzt werden kann. Die Verzögerung bestand darin, den Bereinigungsprozess für Geisterdatensätze ausführen zu lassen.

Da die Lebensdauer zu kurz ist, um 2 Milliarden Duplikate einzufügen, habe ich DBCC WRITEPAGEdie höchste manuell uniqueifierauf 2.147.483.644 eingestellt

Geben Sie hier die Bildbeschreibung ein

Ich rannte dann

INSERT INTO T VALUES (1)

mehrmals. Es war zweimal erfolgreich und schlug beim dritten Versuch mit Fehler 666 fehl.

Dies war tatsächlich eine niedrigere als ich angenommen hätte. Dies bedeutet, dass der höchste eingefügte Uniqueifier 2.147.483.646 anstelle der maximalen int-Größe von 2.147.483.647 war

Martin Smith
quelle
TRUNCATE TABLEKönnen Sie zu Informationszwecken überprüfen, ob der Uniqueifier zurückgesetzt wird?
Jon Seigel
@ JonSeigel - Ja, scheint. Nach dem Ausführen ist INSERT INTO T VALUES (1),(1),(1),(2),(2);TRUNCATE TABLE T;INSERT INTO T VALUES (1),(1),(1),(2),(2)dann der höchste Uniqueifier vermutlich 2 der höchste Uniqueifier, der bereits für diesen Schlüssel existiert (einschließlich Ghost Records)
Martin Smith