MSG 666 podczas uruchamiania zapytania wstawiania w tabeli indeksowanej z wierszem 80 M.

10

O dziwo, moja procedura składowana zaczęła odbierać Msg 666 dla niektórych danych wejściowych.

Procedura przechowywana kończy się niepowodzeniem w ostatnim kroku, gdy próbuje wstawić wiersz do tabeli o następującej strukturze:

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

Zasadniczo jest to tabela, która łączy wszystkie encje, do których istnieją odniesienia.

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)

Fragmentacja obu wskaźników jest niska (<25%). Jednak fragmentacja PK_TableName szybko rośnie, ponieważ ilość operacji na stole jest dość intensywna.

Rozmiar tabeli:

Row count: ~80,000,000 rows

Więc kiedy próbuję uruchomić bardzo proste zapytanie, dla niektórych D_Id pojawia się następujący komunikat:

Msg 666. Przekroczono maksymalną wygenerowaną przez system unikalną wartość dla zduplikowanej grupy dla indeksu o ID partycji 422223771074560. Usunięcie i ponowne utworzenie indeksu może rozwiązać ten problem; w przeciwnym razie użyj innego klucza klastrowania.

Przykład zapytania:

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

Na przykład, gdy ustawię D_Id na niektóre wartości - nie powiedzie się, na przykład „14”. Jeśli ustawię D_ID na inne wartości (1,2,3, ... 13, 15,16, ...), zapytanie będzie działać poprawnie.

Podejrzewam, że z indeksami dzieje się coś naprawdę złego ... Ale nie mogę dojść do sedna tego ... :( Dlaczego to się nie udaje?

Igor Malin
źródło

Odpowiedzi:

16

Wspomniany przez Remusa problem niskiej selektywności nie jest sam w sobie wystarczający, aby spowodować problem w tej tabeli rozmiarów.

Unikalizator zaczyna się od 1i może wzrosnąć, 2,147,483,646zanim faktycznie przepełni zakres.

Wymaga to również prawidłowego wzorca powtarzających się operacji usuwania i wstawiania, aby zobaczyć problem.

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)

Daje

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

Potem biegnij

DELETE FROM T 
WHERE Y IN (2,3)

INSERT INTO T VALUES (1),(1)

Daje

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

W takim przypadku unikatnik nie użył ponownie wartości z usuniętych wierszy.

Jednak potem działa

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

Daje

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

Pokazuje, że znak wysokiej wody można zresetować po usunięciu duplikatu z najwyższą wartością unikalizatora. Opóźnienie miało pozwolić na uruchomienie procesu czyszczenia rekordów duchów.

Ponieważ życie jest zbyt krótkie, aby wstawić 2 miliardy duplikatów, użyłem następnie DBCC WRITEPAGEręcznie dostosować najwyższą uniqueifierdo 2 147 483 644

wprowadź opis zdjęcia tutaj

Wtedy pobiegłem

INSERT INTO T VALUES (1)

wiele razy. Udało się to dwukrotnie i nie powiodło się przy trzeciej próbie z błędem 666.

To był o jeden niższy poziom niż się spodziewałam. Oznacza to, że najwyższy wstawiony unikalizator wynosił 2 147 483 646, a nie maksymalny rozmiar int 2147 483 647

Martin Smith
źródło
Czy w celach informacyjnych możesz sprawdzić, czy TRUNCATE TABLEresetuje unikalizator?
Jon Seigel,
@JonSeigel - Tak, wydaje się. Po uruchomieniu INSERT INTO T VALUES (1),(1),(1),(2),(2);TRUNCATE TABLE T;INSERT INTO T VALUES (1),(1),(1),(2),(2)najwyższy unikalizator 2 zakłada, że ​​wygląda na najwyższy unikalizator, który już istnieje dla tego klucza (w tym zapisów o duchach)
Martin Smith,