ผงชูรส 666 เมื่อเรียกใช้แบบสอบถามแทรกในตารางดัชนี 80M แถว


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

ดังนั้นเมื่อฉันพยายามเรียกใช้แบบสอบถามอย่างง่าย veeery สำหรับ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, ... ) แบบสอบถามจะทำงานได้ดี

ฉันสงสัยว่ามีบางอย่างไม่ดีที่เกิดขึ้นกับดัชนี ... แต่ฉันไม่สามารถไปถึงจุดต่ำสุดของสิ่งนี้ ... :( ทำไมมันถึงล้มเหลว?

คำตอบ:


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

แสดงว่าสามารถตั้งค่าเครื่องหมายน้ำสูงได้หลังจากลบสำเนาที่ซ้ำกันด้วยค่าตัวระบุเฉพาะสูงสุด ความล่าช้าคือการอนุญาตให้กระบวนการล้างระเบียนผีทำงาน

เพราะชีวิตสั้นเกินไปที่จะแทรก 2 ซ้ำซ้อนฉันจึงใช้DBCC WRITEPAGEการปรับค่าสูงสุดด้วยตนเองuniqueifierถึง 2,147,483,644

ป้อนคำอธิบายรูปภาพที่นี่

จากนั้นฉันก็วิ่ง

INSERT INTO T VALUES (1)

หลายครั้ง. มันประสบความสำเร็จสองครั้งและล้มเหลวในความพยายามครั้งที่สามที่มีข้อผิดพลาด 666

อันนี้จริง ๆ แล้วต่ำกว่าที่ฉันคิดเอาไว้ หมายความว่าตัวแทรกพิเศษสูงสุดคือ 2,147,483,646 แทนที่จะเป็นขนาด int สูงสุดของ 2,147,483,647


เพื่อจุดประสงค์ในการให้ข้อมูลคุณสามารถตรวจสอบว่ามีการTRUNCATE TABLEรีเซ็ตตัวระบุซ้ำหรือไม่
Jon Seigel

@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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.