MSG 666 lors de l'exécution d'une requête d'insertion sur une table indexée de 80 millions de lignes

10

Étrangement, ma procédure stockée a commencé à recevoir Msg 666 pour certaines données d'entrée.

La procédure stockée échoue à la dernière étape lorsqu'elle essaie d'insérer une ligne dans une table avec la structure suivante:

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

Il s'agit essentiellement d'un tableau qui relie toutes les entités référencées entre elles.

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)

La fragmentation des deux indices est faible (<25%). Cependant, la fragmentation PK_TableName augmente rapidement, car la quantité d'opérations sur la table est assez intense.

Taille de la table:

Row count: ~80,000,000 rows

Ainsi, lorsque j'essaie d'exécuter une requête simple veeery, pour certains D_Id, j'obtiens le message suivant:

Msg 666. La valeur unique maximale générée par le système pour un groupe en double a été dépassée pour l'index avec l'ID de partition 422223771074560. La suppression et la recréation de l'index peuvent résoudre ce problème; sinon, utilisez une autre clé de clustering.

Exemple de requête:

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

Par exemple, lorsque j'ai défini D_Id sur certaines valeurs - il échoue, «14» par exemple. Si je mets D_ID à d'autres valeurs (1,2,3, ... 13, 15,16, ...), la requête s'exécute correctement.

Je soupçonne qu'il y a quelque chose de vraiment mauvais avec les index ... Mais je ne peux pas aller au fond des choses ... :( Pourquoi ça échoue?

Igor Malin
la source

Réponses:

16

Le problème de faible sélectivité mentionné par Remus n'est pas suffisant à lui seul pour provoquer le problème sur cette table de taille.

L'unificateur commence à 1et peut remonter 2,147,483,646avant de déborder de la plage.

Il nécessite également le bon schéma de suppressions et d'insertions répétées pour voir le problème.

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)

Donne

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

Puis en cours d'exécution

DELETE FROM T 
WHERE Y IN (2,3)

INSERT INTO T VALUES (1),(1)

Donne

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

Dans ce cas, l'unificateur n'a pas réutilisé les valeurs des lignes supprimées.

Cependant, en cours d'exécution

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

Donne

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

Montrant que la ligne des hautes eaux peut être réinitialisée après la suppression du doublon avec la valeur d'unificateur la plus élevée. Le retard était de permettre au processus de nettoyage des enregistrements fantômes de s'exécuter.

Parce que la durée de vie est trop courte pour insérer 2 milliards de doublons, j'ai ensuite utilisé DBCC WRITEPAGEpour ajuster manuellement le plus élevé uniqueifierà 2.147.483.644

entrez la description de l'image ici

J'ai ensuite couru

INSERT INTO T VALUES (1)

plusieurs fois. Il a réussi deux fois et a échoué à la troisième tentative avec l'erreur 666.

C'était en fait un de moins que je ne l'aurais cru. Cela signifie que l'unificateur le plus élevé inséré était de 2147483646 au lieu de la taille int maximale de 2147483647

Martin Smith
la source
À des fins d'information, pouvez-vous vérifier si la TRUNCATE TABLEréinitialisation de l'unificateur est réinitialisée?
Jon Seigel
@ JonSeigel - Oui, semble-t-il. Après avoir exécuté, INSERT INTO T VALUES (1),(1),(1),(2),(2);TRUNCATE TABLE T;INSERT INTO T VALUES (1),(1),(1),(2),(2)l'unificateur le plus élevé est 2 je suppose qu'il examine l'unificateur le plus élevé qui existe déjà pour cette clé (y compris les enregistrements fantômes)
Martin Smith