SQL Server สามารถสร้างการชนในชื่อข้อ จำกัด ที่ระบบสร้างได้หรือไม่?


14

ฉันมีแอปพลิเคชั่นที่สร้างตารางเป็นล้านตารางในฐานข้อมูล SQL Server 2008 (ไม่ใช่คลัสเตอร์) ฉันต้องการอัพเกรดเป็น SQL Server 2014 (เป็นกลุ่ม) แต่ฉันพบข้อความแสดงข้อผิดพลาดเมื่อโหลดไม่ครบ:

“ มีวัตถุชื่อ 'PK__tablenameprefix__179E2ED8F259C33B' ในฐานข้อมูลอยู่แล้ว "

นี่คือชื่อข้อ จำกัด ที่ระบบสร้างขึ้น ดูเหมือนว่าหมายเลข 64 บิตที่สร้างแบบสุ่ม เป็นไปได้ไหมที่ฉันเห็นการชนเนื่องจากตารางจำนวนมาก? สมมติว่าฉันมี 100 ล้านตารางฉันคำนวณโอกาสน้อยกว่า 1 ใน 1 ล้านล้านของการชนกันเมื่อเพิ่มตารางถัดไป แต่ถือว่าเป็นการกระจายแบบสม่ำเสมอ เป็นไปได้หรือไม่ที่ SQL Server เปลี่ยนอัลกอริธึมการสร้างชื่อระหว่างเวอร์ชั่น 2008 และ 2014 เพื่อเพิ่มโอกาสในการชน?

ความแตกต่างที่สำคัญอื่น ๆ คืออินสแตนซ์ 2014 ของฉันเป็นคู่แบบคลัสเตอร์ แต่ฉันกำลังพยายามตั้งสมมติฐานเพื่อหาสาเหตุที่ทำให้เกิดข้อผิดพลาดด้านบน

ป.ล. ใช่ฉันรู้ว่าการสร้างตารางนับล้านนั้นเสียสติ นี่คือรหัสสีดำของบุคคลที่สามซึ่งฉันไม่สามารถควบคุมได้ แม้จะมีความวิกลจริต แต่ก็ใช้งานได้ในเวอร์ชัน 2008 และตอนนี้ไม่ได้อยู่ในเวอร์ชัน 2014

แก้ไข: เมื่อตรวจสอบอย่างใกล้ชิดคำต่อท้ายที่สร้างขึ้นมักจะเริ่มต้นด้วย 179E2ED8 - หมายถึงส่วนที่สุ่มนั้นเป็นเพียงหมายเลข 32 บิตและอัตราต่อรองของการชนเป็นเพียง 1 ใน 50 ทุกครั้งที่มีการเพิ่มตารางใหม่ ตรงกับอัตราความผิดพลาดที่ฉันเห็นมากขึ้น


ชื่อตารางแตกต่างกัน แต่ใช้หลักการตั้งชื่อซึ่งส่งผลให้อักขระอย่างน้อย 11 ตัวแรกเป็นชื่อเดียวกันและดูเหมือนว่า SQL Server ทั้งหมดจะใช้ในการสร้างชื่อข้อ จำกัด
jl6

ฮาร์ดแวร์พื้นฐานแตกต่างกัน (รุ่นใหม่กว่าของ DL380) แต่ไม่มีประสิทธิภาพที่สูงขึ้นอย่างมีนัยสำคัญ เป้าหมายของแบบฝึกหัดคือการแทนที่ SQL Server 2008 ที่ไม่สนับสนุนซึ่งจะไม่ปรับปรุงปริมาณงานและฮาร์ดแวร์ได้รับการจัดสรรตามลำดับ
jl6

คำตอบ:


16

SQL Server สามารถสร้างการชนในชื่อข้อ จำกัด ที่ระบบสร้างได้หรือไม่?

ขึ้นอยู่กับประเภทของข้อ จำกัด และรุ่นของ SQL Server

CREATE TABLE T1
(
A INT PRIMARY KEY CHECK (A > 0),
B INT DEFAULT -1 REFERENCES T1,
C INT UNIQUE,
CHECK (C > A)
)

SELECT name, 
       object_id, 
       CAST(object_id AS binary(4)) as object_id_hex,
       CAST(CASE WHEN object_id >= 16000057  THEN object_id -16000057 ELSE object_id +2131483591 END AS BINARY(4)) AS object_id_offset_hex
FROM sys.objects
WHERE parent_object_id = OBJECT_ID('T1')
ORDER BY name;

drop table T1

ตัวอย่างผลลัพธ์ปี 2008

+--------------------------+-----------+---------------+----------------------+
|           name           | object_id | object_id_hex | object_id_offset_hex |
+--------------------------+-----------+---------------+----------------------+
| CK__T1__1D498357         | 491357015 | 0x1D498357    | 0x1C555F1E           |
| CK__T1__A__1A6D16AC      | 443356844 | 0x1A6D16AC    | 0x1978F273           |
| DF__T1__B__1B613AE5      | 459356901 | 0x1B613AE5    | 0x1A6D16AC           |
| FK__T1__B__1C555F1E      | 475356958 | 0x1C555F1E    | 0x1B613AE5           |
| PK__T1__3BD019AE15A8618F | 379356616 | 0x169C85C8    | 0x15A8618F           |
| UQ__T1__3BD019A91884CE3A | 427356787 | 0x1978F273    | 0x1884CE3A           |
+--------------------------+-----------+---------------+----------------------+

ตัวอย่างผลลัพธ์ 2017

+--------------------------+------------+---------------+----------------------+
|           name           | object_id  | object_id_hex | object_id_offset_hex |
+--------------------------+------------+---------------+----------------------+
| CK__T1__59FA5E80         | 1509580416 | 0x59FA5E80    | 0x59063A47           |
| CK__T1__A__571DF1D5      | 1461580245 | 0x571DF1D5    | 0x5629CD9C           |
| DF__T1__B__5812160E      | 1477580302 | 0x5812160E    | 0x571DF1D5           |
| FK__T1__B__59063A47      | 1493580359 | 0x59063A47    | 0x5812160E           |
| PK__T1__3BD019AE0A4A6932 | 1429580131 | 0x5535A963    | 0x5441852A           |
| UQ__T1__3BD019A981F522E0 | 1445580188 | 0x5629CD9C    | 0x5535A963           |
+--------------------------+------------+---------------+----------------------+

สำหรับข้อ จำกัด เริ่มต้นให้ตรวจสอบข้อ จำกัด และข้อ จำกัด คีย์ต่างประเทศ 4 ไบต์สุดท้ายของชื่อที่สร้างขึ้นอัตโนมัติเป็นเวอร์ชันเลขฐานสิบหกของ objectid ของข้อ จำกัด ขณะที่objectidมีการรับประกันที่ไม่ซ้ำกันชื่อยังต้องไม่ซ้ำกัน ใน Sybase เกินไปการใช้งานเหล่านี้tabname_colname_objectid

สำหรับข้อ จำกัด ที่ไม่ซ้ำกันและข้อ จำกัด คีย์หลักที่ Sybase ใช้

tabname_colname_tabindid โดยที่ tabindid คือการต่อสตริงของ ID ตารางและ ID ดัชนี

สิ่งนี้จะรับประกันความเป็นเอกลักษณ์ด้วยเช่นกัน

SQL Server ไม่ได้ใช้รูปแบบนี้

ในทั้ง SQL Server 2008 และ 2017 จะใช้สตริง 8 ไบต์ที่ส่วนท้ายของระบบที่สร้างชื่ออย่างไรก็ตามอัลกอริทึมมีการเปลี่ยนแปลงเป็นวิธี 4 ไบต์สุดท้ายของที่ถูกสร้างขึ้น

ในปี 2008 ที่ผ่านมา 4 ไบต์แทนเคาน์เตอร์จำนวนเต็มลงนามที่จะชดเชยจากobject_idโดย-16000057มีการตัดค่าใด ๆ ในเชิงลบไปรอบ ๆ เพื่อ int ลงนามสูงสุด (ความสำคัญของ16000057คือว่านี่คือการเพิ่มขึ้นนำไปใช้ระหว่างสร้างขึ้นอย่างต่อเนื่องobject_id ) สิ่งนี้ยังรับประกันความเป็นเอกลักษณ์

ในปี 2012 ขึ้นไปฉันไม่เห็นรูปแบบใด ๆ เลยระหว่าง object_id ของข้อ จำกัด และจำนวนเต็มที่ได้รับจากการใช้อักขระ 8 ตัวสุดท้ายของชื่อเป็นการแสดงเลขฐานสิบหกของ int ที่ลงนามแล้ว

ชื่อฟังก์ชั่นใน call stack ในปี 2017 แสดงให้เห็นว่าตอนนี้สร้าง GUID ซึ่งเป็นส่วนหนึ่งของกระบวนการสร้างชื่อ (ในปี 2008 ฉันไม่เห็นพูดถึงMDConstraintNameGenerator) ฉันเดาว่านี่คือการให้แหล่งที่มาของการสุ่ม เห็นได้ชัดว่ามันไม่ได้ใช้ทั้ง 16 ไบต์จาก GUID ใน 4 ไบต์ที่เปลี่ยนไประหว่างข้อ จำกัด

ป้อนคำอธิบายลิงก์ที่นี่

ฉันคิดว่าอัลกอริธึมใหม่ได้ถูกทำขึ้นด้วยเหตุผลบางประการอย่างมีประสิทธิภาพโดยเสียค่าใช้จ่ายในการเพิ่มความเป็นไปได้ของการชนในกรณีที่รุนแรงเช่นคุณ

นี่เป็นกรณีทางพยาธิวิทยาเนื่องจากต้องการคำนำหน้าชื่อตารางและชื่อคอลัมน์ของ PK (ตราบเท่าที่นี้มีผลต่ออักขระ 8 ตัวก่อน 8 สุดท้าย) จะเหมือนกันสำหรับหมื่นตารางก่อนที่จะกลายเป็นจริง แต่สามารถทำซ้ำได้ค่อนข้างมาก ได้อย่างง่ายดายด้วยด้านล่าง

CREATE OR ALTER PROC #P
AS
    SET NOCOUNT ON;

    DECLARE @I INT = 0;


    WHILE 1 = 1
      BEGIN
          EXEC ('CREATE TABLE abcdefghijklmnopqrstuvwxyz' + @I + '(C INT PRIMARY KEY)');
          SET @I +=1;
      END 

GO

EXEC #P

ตัวอย่างการรันบน SQL Server 2017 กับฐานข้อมูลที่สร้างขึ้นใหม่ล้มเหลวในเวลาไม่เกินหนึ่งนาที (หลังจากสร้างตาราง 50,931)

เกี่ยวกับข่าวสาร 2714 ระดับ 16 สถานะ 30 บรรทัด 15 มีวัตถุชื่อ 'PK__abcdefgh__3BD019A8175067CE' ในฐานข้อมูลแล้ว เกี่ยวกับข้อความ 1750, ระดับ 16, สถานะ 1, บรรทัด 15 ไม่สามารถสร้างข้อ จำกัด หรือดัชนี ดูข้อผิดพลาดก่อนหน้า


11

สมมติว่าฉันมีตาราง 100 ล้านตารางฉันจะคำนวณโอกาสการชนน้อยกว่า 1 ใน 1 ล้านล้าน

จำไว้ว่านี่เป็น " ปัญหาวันเกิด " คุณไม่ได้พยายามสร้างการชนสำหรับแฮชที่ให้เพียงอย่างเดียว แต่ควรวัดความน่าจะเป็นที่จะไม่มีการชนกันของค่าหลายคู่

ดังนั้นด้วยตาราง N มี N * (N-1) / 2 คู่ดังนั้นที่นี่ประมาณ 10 16คู่ หากความน่าจะเป็นของการชนคือ 2 -64ความน่าจะเป็นของคู่เดียวที่ไม่เกิดการชนกันคือ 1-2 -64แต่มีหลายคู่ดังนั้นความน่าจะเป็นที่จะไม่มีการชนที่นี่เป็นเรื่องเกี่ยวกับ (1-2 -64 ) 10 16หรือมากกว่าเช่น 1 / 10,000 ดูเช่นhttps://preshing.com/20110504/hash-collision-probabilities/

และถ้าเป็นเพียงแฮ็คแบบ 32 บิตความน่าจะเป็นของการชนจะมีค่าข้าม 1/2 ที่ค่า 77k เท่านั้น


2
และเพื่อให้ได้ค่า 77K ในสถานที่แรกโดยไม่ต้องเผชิญหน้ากับการปะทะกันนั้นมีความเป็นไปไม่ได้เลยทีเดียวเนื่องจากคุณจำเป็นต้องโชคดีสำหรับการสร้างก่อนหน้านี้ทั้งหมดก่อนหน้านั้น ฉันสงสัยว่าสิ่งที่เป็นจุดที่น่าจะเป็นของการปะทะกันถึง 50%
Martin Smith
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.