MSG 666 під час запуску вставки в таблиці з індексом 80 рядків


10

Як не дивно, моя збережена процедура почала отримувати Msg 666 для деяких вхідних даних.

Збережена процедура провалюється на останньому кроці, коли вона намагається вставити рядок у таблицю з такою структурою:

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

Це по суті таблиця, яка з'єднує всі посилаються об'єкти разом.

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)

Фрагментація обох показників низька (<25%). Однак фрагментація PK_TableName швидко зростає, оскільки кількість операцій на столі досить інтенсивна.

Розмір таблиці:

Row count: ~80,000,000 rows

Отже, коли я намагаюся запустити простий запит veeery, для деяких D_Id я отримую таке повідомлення:

Msg 666. Максимальне унікальне значення, що генерується системою для подвійної групи, було перевищено для індексу з ідентифікатором розділу 422223771074560. Скасування та повторне створення індексу може вирішити це; в іншому випадку використовуйте інший кластерний ключ.

Приклад запиту:

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

Наприклад, коли я встановлюю D_Id деяким значенням - він не працює, наприклад, "14". Якщо я встановив D_ID іншим значенням (1,2,3, ... 13, 15,16, ...), запит працює нормально.

Я підозрюю, що з індексами відбувається щось по-справжньому погано ... Але я не можу дійти до цього… :( Чому це не вдається?

Відповіді:


16

Проблема низької вибірковості, згадана Ремусом, недостатня сама по собі, щоб викликати проблему в таблиці розмірів.

Унікалізатор запускається 1і може піднятися до того, 2,147,483,646як фактично переповнить діапазон.

Також для отримання проблеми потрібна правильна схема повторного видалення та вставки.

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)

Дає

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

Потім біг

DELETE FROM T 
WHERE Y IN (2,3)

INSERT INTO T VALUES (1),(1)

Дає

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

Показуючи в цьому випадку унікальний код не використовував повторно значення з видалених рядків.

Однак потім працює

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

Дає

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

Показано, що мітка високої води може бути скинута після видалення дубліката з найвищим значенням уніфікатора. Затримка полягала в тому, щоб дозволити запустити процес очищення записів привидів.

Оскільки життя надто коротке, щоб вставити 2 мільярди дублікатів, я тоді DBCC WRITEPAGEвручну відрегулював найвищі показники uniqueifierдо 2147,483,644

введіть тут опис зображення

Я тоді побігла

INSERT INTO T VALUES (1)

кілька разів. Це вдалося двічі і не вдалося в третій спробі з помилкою 666.

Це було насправді на один нижчий, ніж я міг би припустити. Це означає, що найвищий вставлений унікалізатор був 2,147,483,646, а не максимальний розмір int 2,147,483,647


В інформаційних цілях ви можете перевірити, чи TRUNCATE TABLEскидає унікальний код?
Джон Сейгель

@JonSeigel - Так, здається. Після запуску, INSERT INTO T VALUES (1),(1),(1),(2),(2);TRUNCATE TABLE T;INSERT INTO T VALUES (1),(1),(1),(2),(2)то найвищий уніфікатор - 2 я припускаю, він дивиться на найвищий унікальний код, який вже існує для цього ключа (включаючи записи про привидів)
Мартін Сміт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.