ฉันใช้ varchar (36) หรือมีวิธีที่ดีกว่านี้หรือไม่?
ฉันใช้ varchar (36) หรือมีวิธีที่ดีกว่านี้หรือไม่?
คำตอบ:
DBA ของฉันถามฉันเมื่อฉันถามเกี่ยวกับวิธีที่ดีที่สุดในการจัดเก็บ GUID สำหรับวัตถุของฉันทำไมฉันต้องเก็บ 16 ไบต์เมื่อฉันสามารถทำสิ่งเดียวกันใน 4 ไบต์ด้วย Integer เนื่องจากเขาใช้ความท้าทายนั้นกับฉันฉันคิดว่าตอนนี้เป็นเวลาที่ดีที่จะพูดถึงมัน ที่ถูกกล่าวว่า ...
คุณสามารถจัดเก็บ guid เป็นไบนารี CHAR (16) หากคุณต้องการใช้พื้นที่เก็บข้อมูลให้เกิดประโยชน์สูงสุด
ฉันจะเก็บมันไว้เป็นถ่าน (36)
-
ของ
การเพิ่มคำตอบโดย ThaBadDawg ใช้ฟังก์ชั่นที่มีประโยชน์เหล่านี้ (ขอบคุณเพื่อนร่วมงานที่ชาญฉลาดของฉัน) เพื่อรับจากสตริงความยาว 36 กลับไปเป็นอาร์เรย์ไบต์ที่ 16
DELIMITER $$
CREATE FUNCTION `GuidToBinary`(
$Data VARCHAR(36)
) RETURNS binary(16)
DETERMINISTIC
NO SQL
BEGIN
DECLARE $Result BINARY(16) DEFAULT NULL;
IF $Data IS NOT NULL THEN
SET $Data = REPLACE($Data,'-','');
SET $Result =
CONCAT( UNHEX(SUBSTRING($Data,7,2)), UNHEX(SUBSTRING($Data,5,2)),
UNHEX(SUBSTRING($Data,3,2)), UNHEX(SUBSTRING($Data,1,2)),
UNHEX(SUBSTRING($Data,11,2)),UNHEX(SUBSTRING($Data,9,2)),
UNHEX(SUBSTRING($Data,15,2)),UNHEX(SUBSTRING($Data,13,2)),
UNHEX(SUBSTRING($Data,17,16)));
END IF;
RETURN $Result;
END
$$
CREATE FUNCTION `ToGuid`(
$Data BINARY(16)
) RETURNS char(36) CHARSET utf8
DETERMINISTIC
NO SQL
BEGIN
DECLARE $Result CHAR(36) DEFAULT NULL;
IF $Data IS NOT NULL THEN
SET $Result =
CONCAT(
HEX(SUBSTRING($Data,4,1)), HEX(SUBSTRING($Data,3,1)),
HEX(SUBSTRING($Data,2,1)), HEX(SUBSTRING($Data,1,1)), '-',
HEX(SUBSTRING($Data,6,1)), HEX(SUBSTRING($Data,5,1)), '-',
HEX(SUBSTRING($Data,8,1)), HEX(SUBSTRING($Data,7,1)), '-',
HEX(SUBSTRING($Data,9,2)), '-', HEX(SUBSTRING($Data,11,6)));
END IF;
RETURN $Result;
END
$$
CHAR(16)
เป็นจริงBINARY(16)
เลือกรสชาติที่คุณต้องการ
หากต้องการติดตามโค้ดให้ดีขึ้นนำตัวอย่างที่ระบุให้กับ GUID ที่สั่งซื้อด้วยหลักด้านล่าง (อักขระที่ผิดกฎหมายถูกใช้เพื่อจุดประสงค์ในการอธิบาย - แต่ละที่มีอักขระที่ไม่ซ้ำกัน) ฟังก์ชันจะแปลงลำดับไบต์เพื่อให้ได้ลำดับบิตสำหรับการจัดกลุ่มดัชนีที่ดีกว่า guid ที่จัดลำดับใหม่แสดงไว้ด้านล่างตัวอย่าง
12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
78563412-BC9A-FGDE-HIJK-LMNOPQRSTUVW
ลบเครื่องหมายขีดคั่น:
123456789ABCDEFGHIJKLMNOPQRSTUVW
78563412BC9AFGDEHIJKLMNOPQRSTUVW
GuidToBinary
($ guid char (36)) ผลตอบแทนไบนารี (16) กลับมาอีกครั้ง CONCAT (UNHEX (SUBSTRING ($ guid, 7, 2)) 5, 2), UNHEX (SUBSTRING ($ guid, 3, 2)), UNHEX (SUBSTRING ($ guid, 1, 2)), UNHEX (SUBSTRING ($ guid, 12, 2)), UNHEX (SUBSTRING ($ guid, 10, 2), UNHEX (SUBSTRING ($ guid, 17, 2)), UNHEX (SUBSTRING ($ guid, 15, 2)), UNHEX (SUBSTRING ($ guid, 20, 4)), UNHEX (SUBSTRING ($ guid, 25, 12)));
ถ่าน (36) จะเป็นทางเลือกที่ดี นอกจากนี้ยังสามารถใช้ฟังก์ชั่น UUID () ของ MySQL ซึ่งส่งกลับรูปแบบข้อความ 36 ตัวอักษร (ฐานสิบหกพร้อมยัติภังค์) ซึ่งสามารถใช้สำหรับการดึงข้อมูล ID ดังกล่าวจาก db
"ดีกว่า" ขึ้นอยู่กับสิ่งที่คุณปรับให้เหมาะสม
ขนาดของคุณ / ประสิทธิภาพการจัดเก็บเทียบกับความสะดวกในการพัฒนาเท่าไหร่ สำคัญกว่า - คุณสร้าง GUID ให้เพียงพอหรือดึงข้อมูลเหล่านั้นบ่อยเพียงพอหรือไม่
หากคำตอบคือ "ไม่" char(36)
ก็ดีเกินพอและมันทำให้การจัดเก็บ / ดึงข้อมูล GUIDs นั้นตายง่าย มิฉะนั้นbinary(16)
ก็สมเหตุสมผล แต่คุณจะต้องพึ่งพา MySQL และ / หรือภาษาการเขียนโปรแกรมที่คุณเลือกเพื่อแปลงไปมาจากการแสดงสตริงปกติ
ไบนารี (16) น่าจะดีกว่าการใช้ varchar (32)
GuidToBinary ขั้นตอนการโพสต์โดย KCD ควร tweaked บัญชีสำหรับรูปแบบบิตของการประทับเวลาในสตริง GUID หากสตริงแสดงถึง UUID เวอร์ชัน 1 เช่นเดียวกับที่ส่งคืนโดยรูทีน uuid () mysql ดังนั้นคอมโพเนนต์เวลาจะถูกฝังในตัวอักษร 1-G โดยไม่รวมตัว D
12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
12345678 = least significant 4 bytes of the timestamp in big endian order
9ABC = middle 2 timestamp bytes in big endian
D = 1 to signify a version 1 UUID
EFG = most significant 12 bits of the timestamp in big endian
เมื่อคุณแปลงเป็นไบนารีลำดับที่ดีที่สุดสำหรับการจัดทำดัชนีคือ: EFG9ABC12345678D + ส่วนที่เหลือ
คุณไม่ต้องการสลับ 12345678 ถึง 78563412 เนื่องจาก endian ใหญ่ให้ผลดัชนีไบท์ดัชนีไบต์ที่ดีที่สุดแล้ว อย่างไรก็ตามคุณต้องการให้ไบต์ที่สำคัญที่สุดย้ายไปอยู่ด้านหน้าไบต์ที่ต่ำกว่า ดังนั้น EFG จะไปก่อนตามด้วยบิตกลางและบิตต่ำกว่า สร้างโหลหรือมากกว่านั้นด้วย UUID () ในเวลาไม่กี่นาทีและคุณควรดูว่าคำสั่งนี้ให้อันดับที่ถูกต้องอย่างไร
select uuid(), 0
union
select uuid(), sleep(.001)
union
select uuid(), sleep(.010)
union
select uuid(), sleep(.100)
union
select uuid(), sleep(1)
union
select uuid(), sleep(10)
union
select uuid(), 0;
/* output */
6eec5eb6-9755-11e4-b981-feb7b39d48d6
6eec5f10-9755-11e4-b981-feb7b39d48d6
6eec8ddc-9755-11e4-b981-feb7b39d48d6
6eee30d0-9755-11e4-b981-feb7b39d48d6
6efda038-9755-11e4-b981-feb7b39d48d6
6f9641bf-9755-11e4-b981-feb7b39d48d6
758c3e3e-9755-11e4-b981-feb7b39d48d6
UUID สองตัวแรกถูกสร้างขึ้นใกล้เคียงกับเวลา พวกเขาแตกต่างกันใน 3 nibbles สุดท้ายของบล็อกแรกเท่านั้น นี่เป็นบิตที่มีนัยสำคัญน้อยที่สุดของการประทับเวลาซึ่งหมายความว่าเราต้องการผลักดันมันไปทางขวาเมื่อเราแปลงมันเป็นอาร์เรย์ไบต์ที่ทำดัชนีได้ เป็นตัวอย่างตัวนับ ID สุดท้ายเป็นข้อมูลล่าสุด แต่อัลกอริทึมการสลับของ KCD จะใส่ไว้ก่อน ID 3 (3e ก่อน dc, ไบต์สุดท้ายจากบล็อกแรก)
ลำดับที่ถูกต้องสำหรับการจัดทำดัชนีจะเป็น:
1e497556eec5eb6...
1e497556eec5f10...
1e497556eec8ddc...
1e497556eee30d0...
1e497556efda038...
1e497556f9641bf...
1e49755758c3e3e...
ดูบทความนี้สำหรับข้อมูลสนับสนุน: http://mysql.rjweb.org/doc.php/uuid
*** โปรดทราบว่าฉันไม่แยกแทะเวอร์ชันออกจากการประทับเวลาสูง 12 บิต นี่คือตอด D จากตัวอย่างของคุณ ฉันแค่โยนมันไปด้านหน้า ดังนั้นเลขฐานสองของฉันก็คือ DEFG9ABC เป็นต้น นี่ก็หมายความว่า UUID ที่ทำดัชนีของฉันทั้งหมดเริ่มต้นด้วยแทะเดียวกัน บทความทำสิ่งเดียวกัน
สำหรับผู้ที่เพิ่งสะดุดกับเรื่องนี้ตอนนี้มีทางเลือกที่ดีกว่ามากตามการวิจัยโดย Percona
ประกอบด้วยการจัดระเบียบ UUID ชิ้นใหม่สำหรับการจัดทำดัชนีที่เหมาะสมจากนั้นแปลงเป็นไบนารีเพื่อลดการจัดเก็บ
อ่านบทความเต็มได้ที่นี่
ฉันขอแนะนำให้ใช้ฟังก์ชั่นด้านล่างนี้เนื่องจากสิ่งที่ @ bigh_29 พูดถึงเปลี่ยน guids ของฉันเป็นสิ่งใหม่ (ด้วยเหตุผลที่ฉันไม่เข้าใจ) นอกจากนี้สิ่งเหล่านี้ก็เร็วขึ้นเล็กน้อยในการทดสอบที่ฉันทำบนโต๊ะของฉัน https://gist.github.com/damienb/159151
DELIMITER |
CREATE FUNCTION uuid_from_bin(b BINARY(16))
RETURNS CHAR(36) DETERMINISTIC
BEGIN
DECLARE hex CHAR(32);
SET hex = HEX(b);
RETURN LOWER(CONCAT(LEFT(hex, 8), '-', MID(hex, 9,4), '-', MID(hex, 13,4), '-', MID(hex, 17,4), '-', RIGHT(hex, 12)));
END
|
CREATE FUNCTION uuid_to_bin(s CHAR(36))
RETURNS BINARY(16) DETERMINISTIC
RETURN UNHEX(CONCAT(LEFT(s, 8), MID(s, 10, 4), MID(s, 15, 4), MID(s, 20, 4), RIGHT(s, 12)))
|
DELIMITER ;
หากคุณมีค่า char / varchar จัดรูปแบบเป็น GUID มาตรฐานคุณสามารถเก็บเป็น BINARY (16) โดยใช้ CAST แบบง่าย (MyString AS BINARY16) โดยไม่มีลำดับที่น่าเหลือเชื่อของ CONCAT + SUBSTR
ฟิลด์ BINARY (16) จะถูกเปรียบเทียบ / เรียงลำดับ / จัดทำดัชนีเร็วกว่าสตริงมากและยังใช้พื้นที่น้อยลงสองเท่าในฐานข้อมูล
select CAST("hello world, this is as long as uiid" AS BINARY(16));
ผลิตhello world, thi