MSG 666 ao executar uma consulta de inserção na tabela indexada de 80M


10

Estranhamente, meu procedimento armazenado começou a receber a mensagem 666 para alguns dados de entrada.

O procedimento armazenado falha na última etapa quando tenta inserir uma linha em uma tabela com a seguinte estrutura:

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

Esta é essencialmente uma tabela que conecta todas as entidades referenciadas.

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)

A fragmentação para ambos os índices é baixa (<25%). No entanto, a fragmentação de PK_TableName aumenta rapidamente, pois a quantidade de operações na tabela é bastante intensa.

Tamanho da tabela:

Row count: ~80,000,000 rows

Portanto, quando tento executar uma consulta muito simples, para alguns dos D_Id, recebo a seguinte mensagem:

Msg 666. O valor exclusivo máximo gerado pelo sistema para um grupo duplicado foi excedido para o índice com o ID da partição 422223771074560. Descartar e recriar o índice podem resolver isso; caso contrário, use outra chave de cluster.

Exemplo de consulta:

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

Por exemplo, quando defino D_Id com alguns valores - ele falha, '14' por exemplo. Se eu definir D_ID para outros valores (1,2,3, ... 13, 15,16, ...), a consulta funcionará bem.

Eu suspeito que há algo realmente ruim acontecendo com os índices ... Mas não consigo chegar ao fundo disso ... :( Por que falha?

Respostas:


16

O problema de baixa seletividade mencionado por Remus não é suficiente por si só para causar o problema nessa tabela de tamanho.

O uniqueifier inicia em 1e pode ir até 2,147,483,646antes de realmente ultrapassar o intervalo.

Também requer o padrão correto de exclusões e inserções repetidas para ver o problema.

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 |
+---+---+-------------+

Então correndo

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 |
+---+---+-------------+

Mostrando nesse caso, o uniqueifier não reutilizou os valores das linhas excluídas.

No entanto, em execução

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 |
+---+---+-------------+

Mostrando que a marca d'água alta pode ser redefinida após a exclusão da duplicata com o valor mais alto do exclusivo. O atraso foi para permitir a execução do processo de limpeza de registros fantasmas.

Como a vida é muito curta para inserir 2 bilhões de duplicatas, eu costumava DBCC WRITEPAGEajustar manualmente o valor mais alto uniqueifierpara 2.147.483.644

insira a descrição da imagem aqui

Então eu corri

INSERT INTO T VALUES (1)

várias vezes. Ele conseguiu duas vezes e falhou na terceira tentativa com o erro 666.

Este foi realmente um menor do que eu teria assumido. O que significa que o maior exclusivo identificador inserido foi 2.147.483.646 em vez do tamanho máximo int de 2.147.483.647


Para fins informativos, você pode verificar se TRUNCATE TABLEredefine o exclusivo?
9139 Jon Seigel

@ JonSeigel - Sim, parece. Após a execução INSERT INTO T VALUES (1),(1),(1),(2),(2);TRUNCATE TABLE T;INSERT INTO T VALUES (1),(1),(1),(2),(2), em seguida, a maior uniqueifier é 2 presumo que olha para o mais alto uniqueifier que já existe para essa chave (incluindo registros fantasmas)
Martin Smith
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.