มีบทลงโทษสำหรับการใช้ BINARY (16) แทนที่จะเป็น UNIQUEIDENTIFIER หรือไม่?


19

ฉันเพิ่งได้รับมรดกฐานข้อมูล SQL Server ที่ใช้BINARY(16)แทนUNIQUEIDENTIFIERการจัดเก็บ Guids มันทำสิ่งนี้สำหรับทุกสิ่งรวมถึงกุญแจหลัก

ฉันควรจะกังวลหรือไม่


มันใช้เลขฐานสอง (16) สม่ำเสมอหรือไม่? รวมถึงตัวแปรและพารามิเตอร์หรือไม่ ถ้าไม่คุณต้องพิจารณาผลกระทบของการปลดเปลื้องโดยนัย
Martin Smith

ใช่ขอบคุณที่ฉันไม่ต้องจัดการกับการปลดเปลื้องโดยปริยายเช่นกัน
Jonathan Allen

คำตอบ:


21

ฉันควรจะกังวลหรือไม่

มีบางสิ่งที่นี่ที่เกี่ยวข้องเล็กน้อย

ครั้งแรก:ในขณะที่มันเป็นความจริงที่UNIQUEIDENTIFIER(เช่นGuid) เป็นค่าไบนารี 16 ไบต์ก็เป็นความจริงที่:

  1. ข้อมูลทั้งหมดจะถูกเก็บไว้ในรูปแบบไบนารี (เช่นINTอาจจะเก็บไว้ในBINARY(4), DATETIMEสามารถเก็บไว้ในBINARY(8)ฯลฯ ) จึง # 2 ↴
  2. อาจมีเหตุผลในการมีประเภทข้อมูลแยกต่างหากสำหรับ GUID ที่อยู่นอกเหนือความสะดวกสบาย (เช่นsysnameเป็นชื่อแทนNVARCHAR(128))

ความแตกต่างของพฤติกรรมสามอย่างที่ฉันสามารถหาได้คือ:

  • การเปรียบเทียบUNIQUEIDENTIFIERค่าใน SQL Server สำหรับดีกว่าหรือแย่กว่านั้นไม่ได้ทำแบบเดียวกับการเปรียบเทียบBINARY(16)ค่า ตามหน้า MSDN สำหรับการเปรียบเทียบ GUID และค่าตัวระบุที่ไม่ซ้ำกันเมื่อเปรียบเทียบUNIQUEIDENTIFIERค่าใน SQL Server:

    หกไบต์สุดท้ายของค่ามีความสำคัญมากที่สุด

  • แม้ว่าค่าเหล่านี้จะไม่ถูกจัดเรียงบ่อย ๆ แต่มีความแตกต่างเล็กน้อยระหว่างสองประเภทนี้ ตามหน้า MSDN สำหรับเครื่องระบุเอกลักษณ์ :

    การสั่งซื้อไม่ได้ดำเนินการโดยการเปรียบเทียบรูปแบบบิตของค่าทั้งสอง

  • เนื่องจากมีความแตกต่างในวิธีจัดการค่า GUID ระหว่าง SQL Server และ. NET (บันทึกไว้ในหน้า "การเปรียบเทียบ GUID และค่า Uniqueidentifier" ที่ลิงก์ด้านบน) การดึงข้อมูลนี้ออกจาก SQL Server ลงในรหัสแอปอาจไม่ได้รับการจัดการอย่างเหมาะสม รหัสแอพหากจำเป็นต้องจำลองพฤติกรรมการเปรียบเทียบ SQL Server พฤติกรรมนั้นสามารถเลียนแบบได้ด้วยการแปลงเป็น a SqlGuidแต่ผู้พัฒนาจะรู้หรือไม่

ที่สอง:ขึ้นอยู่กับคำสั่งดังต่อไปนี้

มันทำสิ่งนี้สำหรับทุกสิ่งรวมถึงกุญแจหลัก

ฉันจะกังวลโดยทั่วไปสำหรับประสิทธิภาพของระบบโดยใช้ GUID เป็น PK แทนที่จะเป็น Alternate Keys พร้อมกับการใช้INTหรือแม้กระทั่งBIGINTเป็น PK และยิ่งเป็นห่วงว่า GUID PKs เหล่านี้จะเป็นดัชนีแบบกลุ่มหรือไม่

UPDATE

ความคิดเห็นต่อไปนี้จัดทำโดย OP สำหรับคำตอบของ @ Rob นำมาซึ่งความกังวลเพิ่มเติม:

มันอพยพมาจากฉันคิดว่า MySQL

guid ของสามารถเก็บไว้ใน2 รูปแบบไบนารีที่แตกต่างกัน ดังนั้นอาจมีสาเหตุของความกังวลขึ้นอยู่กับ:

  1. ระบบใดที่สร้างการแสดงแบบไบนารีบนและ
  2. หากใช้ค่าสตริงนอกระบบดั้งเดิมเช่นในรหัสแอพหรือมอบให้ลูกค้าเพื่อใช้ในการนำเข้าไฟล์ ฯลฯ

ปัญหาเกี่ยวกับตำแหน่งที่สร้างการแทนแบบไบนารีเกี่ยวข้องกับการเรียงลำดับไบต์ของ 3 รายการแรกจาก 4 "ฟิลด์" หากคุณไปที่ลิงก์ด้านบนไปยังบทความ Wikipedia คุณจะเห็นว่า RFC 4122 ระบุให้ใช้การเข้ารหัส "Big Endian" สำหรับทั้ง 4 ฟิลด์ แต่ Microsoft GUID นั้นระบุโดยใช้ Endianness "Native" สถาปัตยกรรมของ Intel คือ Little Endian ดังนั้นคำสั่งไบต์สำหรับ 3 ฟิลด์แรกจะกลับด้านจากระบบที่ตามหลัง RFC (รวมถึง GUID แบบ Microsoft ที่สร้างบนระบบ Big Endian) เขตข้อมูลแรก "Data 1" คือ 4 ไบต์ หนึ่งใน endianness มันจะแสดงเป็น 0x01020304(สมมุติฐาน) แต่ใน endianness อื่น ๆ 0x04030201มันจะเป็น ดังนั้นหากฐานข้อมูลปัจจุบัน 'BINARY(16)การเป็นตัวแทนไบนารีนั้นถูกสร้างขึ้นบนระบบที่ทำตาม RFC จากนั้นแปลงข้อมูลในBINARY(16)ฟิลด์เป็นวิลUNIQUEIDENTIFIERจะส่งผลให้เกิด GUID ที่แตกต่างจากที่สร้างขึ้นในตอนแรก สิ่งนี้ไม่ได้ก่อให้เกิดปัญหาหากค่าไม่เคยออกจากฐานข้อมูลและค่าจะถูกเปรียบเทียบเพื่อความเท่าเทียมกันเท่านั้นและไม่ได้เรียงลำดับ

UNIQUEIDENTIFIERความกังวลที่มีการสั่งซื้อก็คือว่าพวกเขาจะไม่ได้อยู่ในลำดับเดียวกันหลังจากแปลงไป โชคดีถ้าระบบเดิมจริงๆคือ MySQL แล้วการสั่งซื้อก็ไม่เคยทำบนฐานเป็นตัวแทนในสถานที่แรกตั้งแต่ MySQL เพียง แต่มีการแสดงสตริงของUUID

ความกังวลเกี่ยวกับค่าสตริงที่ใช้ภายนอกฐานข้อมูลจะรุนแรงมากขึ้นอีกครั้งหากมีการสร้างตัวแทนไบนารีนอก Windows / SQL Server เนื่องจากการเรียงลำดับไบต์อาจแตกต่างกันดังนั้น GUID เดียวกันในรูปแบบสตริงจะส่งผลให้มีการแทนค่าไบนารีแบบต่างกัน 2 แบบขึ้นอยู่กับตำแหน่งที่เกิดการแปลง หากรหัสแอปหรือลูกค้าได้รับ GUID ในรูปแบบสตริงว่าABCมาจากรูปแบบไบนารีของ123 และการเป็นตัวแทนไบนารีถูกสร้างขึ้นบนระบบต่อ RFC ดังนั้นการเป็นตัวแทนไบนารีเดียวกัน (เช่น123) จะแปลเป็นรูปแบบสตริงของDEFเมื่อถูกแปลงเป็น กUNIQUEIDENTIFIER. ในทำนองเดียวกันในรูปแบบเดิมของสตริงABCจะแปลงเป็นรูปแบบไบนารีของเมื่อแปลงเป็น456UNIQUEIDENTIFIER

ดังนั้นหาก GUID ไม่เคยออกจากฐานข้อมูลก็ไม่จำเป็นต้องกังวลเกี่ยวกับการสั่งซื้อ หรือถ้าการนำเข้าจาก MySQL ทำได้โดยการแปลงรูปแบบสตริง (เช่นFCCEC3D8-22A0-4C8A-BF35-EC18227C9F40) มันอาจจะโอเค มิฉะนั้นหากมีการมอบ GUID เหล่านั้นให้กับลูกค้าหรือในรหัสแอปคุณสามารถทดสอบเพื่อดูว่าพวกเขาแปลงได้อย่างไรโดยรับมาแปลงผ่านSELECT CONVERT(UNIQUEIDENTIFIER, 'value found outside of the database');และดูว่าคุณพบระเบียนที่คาดหวังหรือไม่ BINARY(16)ถ้าคุณไม่สามารถตรงกับบันทึกแล้วคุณอาจจะต้องเก็บเป็นทุ่งนา

ในทุกโอกาสที่จะไม่มีปัญหา แต่ฉันพูดถึงเรื่องนี้เพราะภายใต้เงื่อนไขที่เหมาะสมอาจมีปัญหา

และ GUID ใหม่จะถูกแทรกอย่างไร? สร้างขึ้นในรหัสแอพไหม

อัพเดท 2

หากคำอธิบายก่อนหน้าของปัญหาที่อาจเกิดขึ้นที่เกี่ยวข้องกับการนำเข้าการเป็นตัวแทนไบนารีของ GUID ที่สร้างขึ้นในระบบอื่นนั้นทำให้สับสนเล็กน้อย (หรือมาก) หวังว่าสิ่งต่อไปนี้จะชัดเจนขึ้นเล็กน้อย:

DECLARE @GUID UNIQUEIDENTIFIER = NEWID();
SELECT @GUID AS [String], CONVERT(BINARY(16), @GUID) AS [Binary];
-- String = 5FED23BE-E52C-40EE-8F45-49664C9472FD
-- Binary = 0xBE23ED5F2CE5EE408F4549664C9472FD
--          BE23ED5F-2CE5-EE40-8F45-49664C9472FD

ในผลลัพธ์ที่แสดงด้านบนค่า "String" และ "Binary" มาจาก GUID เดียวกัน ค่าที่อยู่ใต้บรรทัด "Binary" เป็นค่าเดียวกันกับบรรทัด "Binary" แต่จัดรูปแบบในลักษณะเดียวกับบรรทัด "String" (เช่นลบ "0x" และเพิ่มขีดกลางสี่เส้น) เมื่อเปรียบเทียบกับค่าที่หนึ่งและที่สามพวกเขาจะไม่เหมือนกัน แต่ใกล้เคียงกันมาก: ส่วนขวาสุดทั้งสองเหมือนกัน แต่ส่วนที่เหลือทั้งสามนั้นไม่เหมือนกัน แต่ถ้าคุณดูอย่างใกล้ชิดคุณจะเห็นว่ามันเป็นไบต์เดียวกันในแต่ละส่วนทั้งสามโดยเรียงตามลำดับที่แตกต่างกัน มันอาจจะง่ายกว่าที่จะดูว่าฉันแสดงเฉพาะสามส่วนแรกเหล่านั้นและจำนวนไบต์ดังนั้นมันจะง่ายกว่าที่จะเห็นว่าลำดับของพวกเขาแตกต่างกันอย่างไรระหว่างการรับรองทั้งสอง:

String = 1 5F 2 ED 3 23 4 BE - 5 E5 6 2C - 7 40 8 EE
Binary = 4 BE 3 23 2 ED 1 5F - 6 2C 5 E5 - 8 EE 7 40 (ใน Windows / SQL Server)

ดังนั้นภายในแต่ละกลุ่มการเรียงลำดับของไบต์จะถูกย้อนกลับ แต่เฉพาะใน Windows และ SQL Server อย่างไรก็ตามในระบบที่ติดกับ RFC การแทนแบบไบนารี่จะทำมิเรอร์การแทนแบบ sting เนื่องจากจะไม่มีการกลับรายการของคำสั่งไบต์ใด ๆ

ข้อมูลถูกนำเข้าสู่ SQL Server จาก MySQL อย่างไร ที่นี่มีตัวเลือกน้อย:

SELECT CONVERT(BINARY(16), '5FED23BE-E52C-40EE-8F45-49664C9472FD'),
       CONVERT(BINARY(16), 0x5FED23BEE52C40EE8F4549664C9472FD),
    CONVERT(BINARY(16), CONVERT(UNIQUEIDENTIFIER, '5FED23BE-E52C-40EE-8F45-49664C9472FD'));

ผลตอบแทน:

0x35464544323342452D453532432D3430  
0x5FED23BEE52C40EE8F4549664C9472FD  
0xBE23ED5F2CE5EE408F4549664C9472FD

สมมติว่ามันเป็นไบนารี่ถึงไบนารี่แบบตรง (เช่นแปลง # 2 ด้านบน) ดังนั้นผลลัพธ์ของ GUID หากแปลงเป็นจริงUNIQUEIDENTIFIERจะเป็น:

SELECT CONVERT(UNIQUEIDENTIFIER, 0x5FED23BEE52C40EE8F4549664C9472FD);

ผลตอบแทน:

BE23ED5F-2CE5-EE40-8F45-49664C9472FD

ซึ่งเป็นสิ่งที่ผิด และนั่นทำให้เรามีคำถามสามข้อ:

  1. ข้อมูลถูกนำเข้าสู่ SQL Server อย่างไร
  2. รหัสแอปเขียนด้วยภาษาใด
  3. รหัสแอพทำงานบนแพลตฟอร์มใด

ฉันจะถือว่า GUID นั้นสร้างขึ้นในแอปพลิเคชันเนื่องจากฉันไม่เห็นพวกเขาในฐานข้อมูล
Jonathan Allen

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

2
@JonathanAllen ฉันได้เพิ่มอีกส่วน UPDATE เพื่อหวังว่าจะอธิบายได้ดีขึ้น และไม่การจัดทำดัชนีไม่ควรมีความแตกต่างระหว่างสิ่งเหล่านี้
โซโลมอน Rutzky

"โชคดี" SQL Server จะไม่เปลี่ยนการสั่งซื้อระหว่าง Variant 1 และ Variant 2 - แม้ว่า 'สามารถ' จะถูกเก็บไว้ในดิสก์ที่แตกต่างกัน แต่เป็นการสั่งซื้อที่สับสนเหมือนกัน
user2864740

5

คุณสามารถเป็นห่วงได้เสมอ ;)

ระบบอาจได้รับการโยกย้ายจากระบบอื่นที่ไม่สนับสนุนตัวระบุเฉพาะ มีการประนีประนอมอื่น ๆ ที่คุณไม่รู้หรือไม่?

ผู้ออกแบบอาจไม่ทราบเกี่ยวกับประเภทตัวระบุเฉพาะ พวกเขาไม่รู้อะไรอีกแล้ว

แม้ว่าในทางเทคนิคแล้ว - มันไม่ควรเป็นปัญหาสำคัญ


ใช่มันย้ายมาจากฉันคิดว่า MySQL และใช่มีหลายสิ่ง ... ที่น่าสนใจที่ต้องดู
Jonathan Allen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.