MSG 666 saat menjalankan kueri sisipkan pada tabel indeks di 80M-baris

10

Anehnya, prosedur tersimpan saya mulai menerima Msg 666 untuk beberapa data input.

Prosedur tersimpan gagal pada langkah terakhir ketika mencoba memasukkan baris ke dalam tabel dengan struktur berikut:

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

Ini pada dasarnya adalah tabel yang menghubungkan semua entitas yang dirujuk bersama.

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)

Fragmentasi untuk kedua indeks rendah (<25%). Namun fragmentasi PK_TableName cepat tumbuh, karena jumlah operasi di atas meja cukup kuat.

Ukuran meja:

Row count: ~80,000,000 rows

Jadi, ketika saya mencoba menjalankan query sederhana veeery, untuk beberapa D_Id saya mendapatkan pesan berikut:

Msg 666. Nilai unik yang dihasilkan sistem maksimum untuk grup duplikat terlampaui untuk indeks dengan ID partisi 422223771074560. Menjatuhkan dan membuat kembali indeks dapat menyelesaikan ini; jika tidak, gunakan kunci pengelompokan lain.

Contoh pertanyaan:

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

Misalnya, ketika saya menetapkan D_Id ke beberapa nilai - gagal, '14' misalnya. Jika saya menetapkan D_ID ke nilai lain (1,2,3, ... 13, 15,16, ...), kueri akan berjalan dengan baik.

Saya menduga ada sesuatu yang sangat buruk terjadi dengan indeks ... Tapi saya tidak bisa sampai ke dasar ini ... :( Mengapa gagal?

Igor Malin
sumber

Jawaban:

16

Masalah selektivitas rendah yang disebutkan oleh Remus tidak cukup sendiri untuk menyebabkan masalah pada tabel ukuran itu.

Uniqueifier dimulai pada 1dan dapat naik 2,147,483,646sebelum benar-benar meluap rentang.

Itu juga membutuhkan pola yang tepat dari penghapusan berulang dan menyisipkan untuk melihat masalah.

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)

Memberi

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

Lalu berlari

DELETE FROM T 
WHERE Y IN (2,3)

INSERT INTO T VALUES (1),(1)

Memberi

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

Menampilkan dalam kasus itu, unikifier tidak menggunakan kembali nilai dari baris yang dihapus.

Namun kemudian berjalan

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

Memberi

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

Menunjukkan bahwa tanda air tinggi dapat diatur ulang setelah menghapus duplikat dengan nilai unik tertinggi. Penundaan adalah untuk memungkinkan proses pembersihan catatan hantu berjalan.

Karena hidup terlalu singkat untuk menyisipkan 2 miliar duplikat, saya kemudian terbiasa DBCC WRITEPAGEmenyesuaikan yang tertinggi secara manual uniqueifiermenjadi 2.147.483.644

masukkan deskripsi gambar di sini

Saya kemudian berlari

INSERT INTO T VALUES (1)

beberapa kali. Itu berhasil dua kali dan gagal pada upaya ketiga dengan kesalahan 666.

Ini sebenarnya satu lebih rendah dari yang saya kira. Berarti bahwa unikifier tertinggi yang dimasukkan adalah 2.147.483.646 daripada ukuran int maksimum 2.147.483.647

Martin Smith
sumber
Untuk tujuan informasi, dapatkah Anda memeriksa apakah TRUNCATE TABLEmereset unikifier?
Jon Seigel
@ JonSeigel - Ya, sepertinya. Setelah menjalankan INSERT INTO T VALUES (1),(1),(1),(2),(2);TRUNCATE TABLE T;INSERT INTO T VALUES (1),(1),(1),(2),(2)maka peningkat tertinggi adalah 2 saya kira itu melihat peningkat tertinggi yang sudah ada untuk kunci itu (termasuk catatan hantu)
Martin Smith