मुझे MySQL तालिकाओं में GUID कैसे संग्रहीत करना चाहिए?


146

क्या मैं varchar (36) का उपयोग करता हूं या क्या इसके लिए कोई बेहतर तरीका है?


1
"thaBadDawg" एक अच्छा जवाब देता है। स्टैक ओवरफ्लो पर एक समानांतर धागा है जो विषय पर चर्चा करता है। मैंने कुछ टिप्पणियों को उन थ्रेड्स के उत्तर में जोड़ा है जो संसाधनों के साथ अधिक विस्तार से लिंक करते हैं। यहाँ प्रश्न लिंक है: stackoverflow.com/questions/547118/storing-mysql-guid-uuids - मुझे उम्मीद है कि जब लोग AWS और अरोरा पर विचार करना शुरू करेंगे तो यह विषय और अधिक सामान्य हो जाएगा।
ज़ैक जैनसेन

जवाबों:


104

मेरे डीबीए ने मुझसे पूछा कि जब मैंने अपनी वस्तुओं के लिए GUID को स्टोर करने के सबसे अच्छे तरीके के बारे में पूछा तो मुझे 16 बाइट्स स्टोर करने की आवश्यकता क्यों हुई जब मैं एक ही चीज़ को 4 बाइट्स में एक इंटेगर के साथ कर सकता था। जब से उन्होंने उस चुनौती को मेरे सामने रखा तो मुझे लगा कि अब इसका उल्लेख करने का एक अच्छा समय था। ऐसा कहे जाने के बाद...

आप स्टोरेज (16) बाइनरी के रूप में एक गाइड स्टोर कर सकते हैं यदि आप स्टोरेज स्पेस का सबसे इष्टतम उपयोग करना चाहते हैं।


176
क्योंकि 16 बाइट्स के साथ, आप अलग-अलग डेटाबेस में, अलग-अलग मशीनों पर, अलग-अलग समय पर चीजें पैदा कर सकते हैं, और फिर भी डेटा को मूल रूप से एक साथ मर्ज कर सकते हैं :)
बिली ओपल

4
उत्तर की आवश्यकता है, क्या वास्तव में एक चार 16 बाइनरी है? नहीं चार? बाइनरी नहीं? मैं उस प्रकार के किसी भी mysql gui टूल्स में नहीं देखता, न ही mysql साइट में कोई दस्तावेज। @BillyONeal
nawfal

3
@nawfal: चार डेटाटाइप है। BINARY प्रकार के विरुद्ध विशिष्ट प्रकार है। इसका एकमात्र प्रभाव यह है कि MySQL का कोलाजेशन कैसे संशोधित होता है। अधिक जानकारी के लिए dev.mysql.com/doc/refman/5.0/en/charset-binary-op.html देखें । यदि आपका डेटाबेस संपादन उपकरण आपको ऐसा करने की अनुमति देता है, तो बेशक आप सीधे BINARY प्रकार का उपयोग कर सकते हैं। (पुराने उपकरण बाइनरी डेटा प्रकार के बारे में नहीं जानते हैं लेकिन बाइनरी कॉलम फ्लैग के बारे में जानते हैं)
बिली ओनल

2
एक CHAR और एक BINARY फ़ील्ड अनिवार्य रूप से समान हैं। यदि आप इसे सबसे बुनियादी स्तरों पर ले जाना चाहते हैं, तो एक CHAR एक बाइनरी फ़ील्ड है जिसमें लुकअप टेबल से मैप की गई वैल्यू (अब ज्यादातर मामलों में, UTF8) के साथ उक्त मूल्य का प्रतिनिधित्व करने के इरादे से 0 से 255 मान की उम्मीद है। एक बीनेरी फ़ील्ड लुकअप तालिका से डेटा के प्रतिनिधित्व के किसी भी उद्देश्य के बिना उसी तरह के मूल्य की उम्मीद करता है। मैंने CHAR (16) का उपयोग 4.x दिनों में वापस किया क्योंकि तब MySQL उतना अच्छा नहीं था जितना कि अब है।
thaBadDawg

15
कई अच्छे कारण हैं कि क्यों एक GUID एक ऑटॉइक्रीमेंट से कहीं बेहतर है। जेफ एटवुड इन एक को सूचीबद्ध करता है । मेरे लिए, GUID का उपयोग करने में सबसे अच्छा लाभ यह है कि मेरे ऐप को किसी इकाई की कुंजी जानने के लिए डेटाबेस राउंडट्रिप की आवश्यकता नहीं होगी: मैं इसे प्रोग्रामेटिक रूप से पॉप्युलेट कर सकता हूं, जो कि मैं नहीं कर सकता था यदि मैं एक ऑटो-इन्क्रीमेंट फ़ील्ड का उपयोग कर रहा था। इसने मुझे कई सिरदर्द से बचाया: GUID के साथ मैं इकाई को उसी तरह से प्रबंधित कर सकता हूं, भले ही इकाई पहले से ही बनी हुई हो या यह बिल्कुल नया हो।
एरियलडो मार्टिनी

48

मैं इसे चार (36) के रूप में संग्रहीत करूंगा।


5
मैं नहीं देख सकता कि आपको क्यों स्टोर करना चाहिए -
अफशीन मेहरबानी 15

2
@AfshinMehrabani यह सरल, सीधा, मानव-पठनीय है। यह ज़रूरी नहीं है, लेकिन अगर उन अतिरिक्त बाइट्स को संग्रहीत करना चोट नहीं करता है तो यह सबसे अच्छा समाधान है।
user1717828

2
डैश को संग्रहीत करना एक अच्छा विचार नहीं हो सकता है क्योंकि यह अधिक ओवरहेड का कारण होगा। यदि आप इसे मानव पठनीय बनाना चाहते हैं, तो एप्लिकेशन को डैश के साथ पढ़ें।
लूका फेर्री

@AfshinMehrabani एक अन्य विचार इसे डेटाबेस से पार्स कर रहा है। अधिकांश कार्यान्वयन वैध गाइड में डैश की अपेक्षा करेंगे।
रयान गेट्स

जब आप चार (32) को आसानी से चार (36) में बदलने के लिए लाते हैं, तो आप हाइफ़न डाल सकते हैं। MySql के इन्सर्ट FN का उपयोग करें।
joedotnot

33

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)));
जोनाथन ओलिवर

4
जिज्ञासु के लिए, ये फ़ंक्शन सिर्फ UNHEX (REPLACE (UUID) (, '-', '')) से बेहतर हैं क्योंकि यह बिट्स को एक क्रम में व्यवस्थित करता है जो क्लस्टर किए गए इंडेक्स में बेहतर प्रदर्शन करेगा।
स्लैशटरिक्स

यह बहुत मददगार है, लेकिन मुझे लगता है कि इसके लिए एक स्रोत CHARऔर BINARYसमकक्षता के साथ सुधार किया जा सकता है ( डॉक्स का मतलब है कि महत्वपूर्ण अंतर हैं और पुन: व्यवस्थित बाइट्स के साथ क्लस्टर इंडेक्स का प्रदर्शन बेहतर क्यों है इसकी व्याख्या है।
पैट्रिक एम।

जब मैं इसका उपयोग करता हूं तो मेरा गाइड बदल जाता है। मैंने इसे दोनों unhex (प्रतिस्थापित (स्ट्रिंग, '-', '')) और ऊपर के फ़ंक्शन का उपयोग करके सम्मिलित करने का प्रयास किया है और जब मैं उन्हें उसी विधि का उपयोग करके परिवर्तित करता हूं जो चयनित है, तो वह सम्मिलित नहीं है। क्या है गाइड बदलना? मेरे द्वारा किया गया सभी कोड ऊपर से कॉपी किया गया है।
१४

@JonathanOliver क्या आप बाइनरीटॉइड () फ़ंक्शन के लिए कोड साझा कर सकते हैं?
अरुण अवनाथन

27

चार (36) एक अच्छा विकल्प होगा। इसके अलावा MySQL के UUID () फ़ंक्शन का उपयोग किया जा सकता है जो 36-वर्ण पाठ प्रारूप (हाइफ़न के साथ हेक्स) लौटाता है जिसका उपयोग db से ऐसी आईडी की पुनर्प्राप्ति के लिए किया जा सकता है।


19

"बेहतर" इस ​​बात पर निर्भर करता है कि आप किस चीज के लिए अनुकूलन कर रहे हैं।

आप भंडारण आकार / प्रदर्शन बनाम विकास में आसानी के बारे में कितना ध्यान रखते हैं? इससे भी महत्वपूर्ण बात - क्या आप पर्याप्त GUID बना रहे हैं, या उन्हें अक्सर पर्याप्त रूप से ला रहे हैं, यह मायने रखता है?

यदि उत्तर "नहीं" है, char(36)तो पर्याप्त से अधिक अच्छा है, और यह GUID को मृत-सरल बना देता है। अन्यथा, binary(16)उचित है, लेकिन आपको सामान्य स्ट्रिंग प्रतिनिधित्व से आगे और पीछे बदलने के लिए MySQL और / या अपनी पसंद की प्रोग्रामिंग भाषा पर झुकना होगा।


2
यदि आप सॉफ़्टवेयर होस्ट करते हैं (उदाहरण के लिए एक वेब पेज) और क्लाइंट में नहीं बेचते / इंस्टॉल करते हैं, तो आप सॉफ़्टवेयर के शुरुआती चरण में आसान विकास के लिए हमेशा चार (36) से शुरू कर सकते हैं, और एक अधिक कॉम्पैक्ट के लिए म्यूट कर सकते हैं प्रारूप उपयोग में बढ़ता है और अनुकूलन की आवश्यकता होती है।
ज़ावी मोंटेरो

1
सबसे बड़ा चार (36) का सबसे बड़ा पहलू यह है कि सूचकांक कितना स्थान लेगा। यदि आपके पास डेटाबेस में बड़ी संख्या में रिकॉर्ड हैं, तो आप सूचकांक के आकार को दोगुना कर रहे हैं।
18


7

केसीडी द्वारा पोस्ट की गई गाइडटाइबिनरी रूटीन को 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 एक ही कुतरना के साथ शुरू होते हैं। लेख यही काम करता है।


क्या इसका उद्देश्य संग्रहण स्थान को बचाना है? या उन्हें उपयोगी बनाने के लिए?
एमडी 004

1
@ MD004। यह एक बेहतर सॉर्ट इंडेक्स बनाता है। स्पेस वही रहता है।
bigh_29

5

बस इस पार ठोकर खाने वालों के लिए, पेरकोना के शोध के अनुसार अब एक बेहतर विकल्प है।

इसमें इष्टतम अनुक्रमण के लिए UUID विखंडू को पुनर्गठित करना, फिर कम भंडारण के लिए बाइनरी में परिवर्तित करना शामिल है।

पूरा लेख यहाँ पढ़ें


मैंने वह लेख पहले पढ़ा था। मुझे यह बहुत दिलचस्प लगता है लेकिन फिर हमें एक क्वेरी कैसे करनी चाहिए अगर हम एक आईडी द्वारा फ़िल्टर करना चाहते हैं जो कि बाइनरी है? मुझे लगता है कि हमें फिर से हेक्स करने की आवश्यकता है और फिर मापदंड लागू करें। क्या इसकी इतनी मांग है? बाइनरी (16) को स्टोर करना क्यों सुनिश्चित करें (यह 8 बाइट्स के बिगिंट के बजाय वर्चर (36) से बेहतर है)?
मैक्सिमस डेसीमस


fwiw, UUIDv4 पूरी तरह से रैंडम है और इसमें किसी भी तरह की कोई कमी नहीं है।
महमूद अल-कुद्सी

2

मैं नीचे दिए गए कार्यों का उपयोग करने का सुझाव दूंगा क्योंकि @ 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 ;

-4

यदि आपके पास मानक GUID के रूप में स्वरूपित एक चार / varchar मूल्य है, तो आप इसे CONCAT + SUBSTR के उन सभी मनोदैहिक दृश्यों के बिना, साधारण CAST (MyString AS BINARY16) का उपयोग करके BINARY (16) के रूप में संग्रहीत कर सकते हैं।

BINARY (16) फ़ील्ड्स की तुलना / स्ट्रिंग्स की तुलना में बहुत तेज़ी से की जाती है / अनुक्रमित की जाती है, और डेटाबेस में दो गुना कम जगह लेती है


2
इस क्वेरी को चलाने से पता चलता है कि CAST uuid स्ट्रिंग को ASCII बाइट में परिवर्तित करता है: सेट @a = uuid (); @a, हेक्स (कास्ट (@ ए बायिनरी (16))) का चयन करें; मुझे 16f20d98-9760-11e4-b981-feb7b39d48d6: 3136663230643938 2D 39373630 2D 3131 (स्वरूपण के लिए जोड़े गए स्थान) मिलते हैं। 0x31 = ascii 1, 0x36 = ascii 6. हम भी 0x2D प्राप्त करते हैं, जो कि हाइफ़न है। यह केवल एक स्ट्रिंग के रूप में गाइड को संग्रहीत करने से बहुत अलग नहीं है, सिवाय इसके कि आप स्ट्रिंग को 16 वें वर्ण पर काटते हैं, जो मशीन विशिष्ट आईडी के भाग को बंद कर देता है।
bigh_29

हां, यह केवल छंटनी है। select CAST("hello world, this is as long as uiid" AS BINARY(16));उत्पादनhello world, thi
MD004
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.