क्या मैं varchar (36) का उपयोग करता हूं या क्या इसके लिए कोई बेहतर तरीका है?
क्या मैं varchar (36) का उपयोग करता हूं या क्या इसके लिए कोई बेहतर तरीका है?
जवाबों:
मेरे डीबीए ने मुझसे पूछा कि जब मैंने अपनी वस्तुओं के लिए GUID को स्टोर करने के सबसे अच्छे तरीके के बारे में पूछा तो मुझे 16 बाइट्स स्टोर करने की आवश्यकता क्यों हुई जब मैं एक ही चीज़ को 4 बाइट्स में एक इंटेगर के साथ कर सकता था। जब से उन्होंने उस चुनौती को मेरे सामने रखा तो मुझे लगा कि अब इसका उल्लेख करने का एक अच्छा समय था। ऐसा कहे जाने के बाद...
आप स्टोरेज (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 का उदाहरण लें। (गैरकानूनी वर्णों का उपयोग निदर्शी उद्देश्यों के लिए किया जाता है - प्रत्येक स्थान एक अद्वितीय वर्ण।) फ़ंक्शंस बेहतर अनुक्रमण क्लस्टरिंग के लिए एक बिट ऑर्डर प्राप्त करने के लिए बाइट ऑर्डर को बदल देगा। उदाहरण के नीचे पुन: प्रदर्शित गाइड दिखाया गया है।
12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
78563412-BC9A-FGDE-HIJK-LMNOPQRSTUVW
हटाए गए डैश:
123456789ABCDEFGHIJKLMNOPQRSTUVW
78563412BC9AFGDEHIJKLMNOPQRSTUVW
GuidToBinary
($ गाइड चार (36)) रिटर्न्स बाइनरी (16) रिटेन कॉनसैट (UNHEX (SUBSTRING ($ गाइड, 7, 2))), UNHEX (SUBSTRING ($ गाइड) 5, 2)), UNHEX (SUBSTRING ($ गाइड, 3, 2)), UNHEX (SUBSTRING ($ गाइड, 1, 2)), UNHEX (SUBSTRING ($ गाइड, 12, 2)), UNHEX (SUBSTRING ($) गाइड, 10, 2), UNHEX (SUBSTRING ($ गाइड, 17, 2)), UNHEX (SUBSTRING ($ गाइड, 15, 2)), UNHEX (SUBSTRING ($ गाइड, 20, 4)), UNHEX (SUBSTRING) ($ गाइड, 25, 12)));
CHAR
और BINARY
समकक्षता के साथ सुधार किया जा सकता है ( डॉक्स का मतलब है कि महत्वपूर्ण अंतर हैं और पुन: व्यवस्थित बाइट्स के साथ क्लस्टर इंडेक्स का प्रदर्शन बेहतर क्यों है इसकी व्याख्या है।
चार (36) एक अच्छा विकल्प होगा। इसके अलावा MySQL के UUID () फ़ंक्शन का उपयोग किया जा सकता है जो 36-वर्ण पाठ प्रारूप (हाइफ़न के साथ हेक्स) लौटाता है जिसका उपयोग db से ऐसी आईडी की पुनर्प्राप्ति के लिए किया जा सकता है।
"बेहतर" इस बात पर निर्भर करता है कि आप किस चीज के लिए अनुकूलन कर रहे हैं।
आप भंडारण आकार / प्रदर्शन बनाम विकास में आसानी के बारे में कितना ध्यान रखते हैं? इससे भी महत्वपूर्ण बात - क्या आप पर्याप्त GUID बना रहे हैं, या उन्हें अक्सर पर्याप्त रूप से ला रहे हैं, यह मायने रखता है?
यदि उत्तर "नहीं" है, char(36)
तो पर्याप्त से अधिक अच्छा है, और यह GUID को मृत-सरल बना देता है। अन्यथा, binary(16)
उचित है, लेकिन आपको सामान्य स्ट्रिंग प्रतिनिधित्व से आगे और पीछे बदलने के लिए MySQL और / या अपनी पसंद की प्रोग्रामिंग भाषा पर झुकना होगा।
बाइनरी (16) ठीक होगा, जो कि वार्चर (32) के उपयोग से बेहतर है।
केसीडी द्वारा पोस्ट की गई गाइडटाइबिनरी रूटीन को GUID स्ट्रिंग में टाइमस्टैम्प के बिट लेआउट के लिए खाता होना चाहिए। यदि स्ट्रिंग एक संस्करण 1 यूयूआईडी का प्रतिनिधित्व करता है, जैसे कि यूयूडी () मायस्कल रूटीन द्वारा लौटाए जाते हैं, तो समय घटकों को डी को छोड़कर पत्र 1-जी में एम्बेडेड किया जाता है।
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 पर स्वैप नहीं करना चाहते क्योंकि बड़ा एंडियन पहले से ही सबसे अच्छा बाइनरी इंडेक्स बाइट ऑर्डर देता है। हालाँकि, आप चाहते हैं कि सबसे महत्वपूर्ण बाइट्स निचले बाइट्स के सामने चले जाएं। इसलिए, ईएफजी पहले जाते हैं, उसके बाद मध्य बिट्स और निचले बिट्स। एक मिनट के दौरान एक दर्जन या तो यूयूआईडी (यूयूआईडी) के साथ उत्पन्न करें और आपको यह देखना चाहिए कि यह क्रम कैसे सही रैंक देता है।
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 निबल्स में भिन्न होते हैं। ये टाइमस्टैम्प के कम से कम महत्वपूर्ण बिट्स हैं, जिसका मतलब है कि जब हम इसे इंडेक्सेबल टैट सरणी में बदलते हैं, तो हम उन्हें दाईं ओर धकेलना चाहते हैं। एक काउंटर उदाहरण के रूप में, अंतिम आईडी सबसे अधिक चालू है, लेकिन केसीडी की स्वैपिंग एल्गोरिथ्म इसे 3 डी आईडी (डीसी से पहले 3e, पहले ब्लॉक से अंतिम बाइट्स) से पहले डाल देगा।
अनुक्रमण के लिए सही क्रम होगा:
1e497556eec5eb6...
1e497556eec5f10...
1e497556eec8ddc...
1e497556eee30d0...
1e497556efda038...
1e497556f9641bf...
1e49755758c3e3e...
सहायक जानकारी के लिए यह लेख देखें: http://mysql.rjweb.org/doc.php/uuid
*** ध्यान दें कि मैं टाइमस्टैम्प के उच्च 12 बिट्स से संस्करण को विभाजित नहीं करता हूं। यह आपके उदाहरण से डी nibble है। मैं बस इसे सामने फेंक देता हूं। तो मेरा बाइनरी अनुक्रम DEFG9ABC और इतने पर समाप्त होता है। इसका तात्पर्य है कि मेरे सभी अनुक्रमित UUIDs एक ही कुतरना के साथ शुरू होते हैं। लेख यही काम करता है।
बस इस पार ठोकर खाने वालों के लिए, पेरकोना के शोध के अनुसार अब एक बेहतर विकल्प है।
इसमें इष्टतम अनुक्रमण के लिए UUID विखंडू को पुनर्गठित करना, फिर कम भंडारण के लिए बाइनरी में परिवर्तित करना शामिल है।
पूरा लेख यहाँ पढ़ें
मैं नीचे दिए गए कार्यों का उपयोग करने का सुझाव दूंगा क्योंकि @ bigh_29 द्वारा उल्लिखित मेरे छापों को नए लोगों में बदल देता है (उन कारणों के लिए जो मुझे समझ में नहीं आते हैं)। इसके अलावा, मैंने अपने टेबलों पर जो परीक्षण किए हैं, उनमें ये थोड़ा तेज हैं।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 ;
यदि आपके पास मानक GUID के रूप में स्वरूपित एक चार / varchar मूल्य है, तो आप इसे CONCAT + SUBSTR के उन सभी मनोदैहिक दृश्यों के बिना, साधारण CAST (MyString AS BINARY16) का उपयोग करके BINARY (16) के रूप में संग्रहीत कर सकते हैं।
BINARY (16) फ़ील्ड्स की तुलना / स्ट्रिंग्स की तुलना में बहुत तेज़ी से की जाती है / अनुक्रमित की जाती है, और डेटाबेस में दो गुना कम जगह लेती है
select CAST("hello world, this is as long as uiid" AS BINARY(16));
उत्पादनhello world, thi