在80M行索引表上运行插入查询时,MSG 666


10

奇怪的是,我的存储过程开始收到某些输入数据的消息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

因此,当我尝试运行简单的查询时,对于某些D_Id,我会收到以下消息:

消息666。对于分区ID为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,...),则查询运行正常。

我怀疑索引确实发生了一些非常糟糕的事情……但是我无法深入了解……:(为什么失败了?

Answers:


16

Remus提到的低选择性问题本身不足以在该尺寸表上引起问题。

唯一标识符起始于,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 |
+---+---+-------------+

表明删除具有最高唯一性值的副本后可以重置高水位线。延迟是为了允许幻影记录清除过程运行。

由于寿命太短,无法插入20亿份副本,因此我用DBCC WRITEPAGE手动将最高值调整uniqueifier为2,147,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 我认为最高的唯一标识符是针对该键(包括幽灵记录)的已存在的最高唯一标识符
Martin Smith
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.