MySQL में UUID का प्रदर्शन?


86

हम अपने MySQL डेटाबेस के लिए प्राथमिक कुंजी के रूप में UUID मानों का उपयोग करने पर विचार कर रहे हैं। डाला जा रहा डेटा दर्जनों, सैकड़ों, या यहां तक ​​कि हजारों दूरस्थ कंप्यूटरों से उत्पन्न होता है और प्रति सेकंड 100-40,000 आवेषण की दर से डाला जाता है, और हम कभी भी कोई अपडेट नहीं करेंगे।

डेटाबेस स्वयं आमतौर पर लगभग ५० एम रिकॉर्ड प्राप्त कर लेगा, इससे पहले कि हम डेटा को लेना शुरू कर दें, इतना बड़ा डेटाबेस नहीं, लेकिन छोटा भी नहीं। हम भी InnoDB पर चलने की योजना बना रहे हैं, हालांकि हम यह बदलने के लिए खुले हैं कि अगर हम जो कर रहे हैं उसके लिए एक बेहतर इंजन है।

हम जावा के टाइप 4 यूयूआईडी के साथ जाने के लिए तैयार थे, लेकिन परीक्षण में कुछ अजीब व्यवहार देख रहे हैं। एक के लिए, हम varchar (36) के रूप में स्टोर कर रहे हैं और मुझे अब एहसास हुआ कि हम बाइनरी (16) का उपयोग करना बेहतर होगा - हालांकि मैं कितना बेहतर हूं, मुझे यकीन नहीं है।

बड़ा सवाल यह है: जब हम 50M रिकॉर्ड रखते हैं तो यह यादृच्छिक डेटा सूचकांक को कितनी बुरी तरह से पेंच करता है? यदि हम उपयोग करते हैं, तो क्या हम बेहतर होंगे, उदाहरण के लिए, टाइप -1 यूयूआईडी जहां बाईं ओर के बिटस्टैम्प थे? या हो सकता है कि हमें UUIDs को पूरी तरह से खोद देना चाहिए और auto_increment प्राथमिक कुंजी पर विचार करना चाहिए?

जब मैं MySQL में सूचकांक / प्राथमिक कुंजी के रूप में संग्रहीत किया जाता है, तो मैं विभिन्न प्रकार के UUIDs के प्रदर्शन पर सामान्य विचारों / युक्तियों की तलाश कर रहा हूं। धन्यवाद!


2
एक महत्वपूर्ण विवरण अनुपलब्ध है: लॉगिंग सर्वर या क्लाइंट मशीनों द्वारा स्वयं उत्पन्न की जाने वाली प्राथमिक कुंजियाँ हैं?

1
@ वे 10-1000 ग्राहकों द्वारा उत्पन्न किए जा रहे हैं जो डेटा डालते हैं
पैट्रिक लाइटबॉडी

आपको अपने परिदृश्य में सार्वभौमिक विशिष्टता की आवश्यकता कहां है? मेरी सलाह यह है कि डेटा भेजने वाले दूरस्थ कंप्यूटर का वर्णन करने के लिए auto_increment से चिपके रहें और एक अलग फ़ील्ड का उपयोग करें। यहां पहिया को सुदृढ़ करने की आवश्यकता नहीं है।
थियोडोर जोगोस

जवाबों:


36

एक UUID एक यूनिवर्सली यूनिक आईडी है। यह सार्वभौमिक रूप से हिस्सा है जिसे आपको यहां पर विचार करना चाहिए।

क्या आपको वास्तव में सार्वभौमिक रूप से विशिष्ट होने के लिए आईडी की आवश्यकता है? यदि हां, तो यूयूआईडी आपकी एकमात्र पसंद हो सकती है।

मैं दृढ़ता से सुझाव दूंगा कि यदि आप यूयूआईडी का उपयोग करते हैं, तो आप उन्हें एक संख्या के रूप में संग्रहीत करते हैं, न कि एक स्ट्रिंग के रूप में। यदि आपके पास 50M + रिकॉर्ड है, तो स्टोरेज स्पेस में बचत करने से आपके प्रदर्शन में सुधार होगा (हालांकि मैं यह नहीं कह सकता कि कितना)।

यदि आपकी आईडी को सार्वभौमिक रूप से विशिष्ट होने की आवश्यकता नहीं है, तो मुझे नहीं लगता है कि आप ज्यादा बेहतर कर सकते हैं, तो बस auto_increment का उपयोग कर सकते हैं, जो गारंटी देता है कि आईडी एक तालिका के भीतर अद्वितीय होगी (क्योंकि मूल्य हर बार वृद्धि होगी)


2
दिलचस्प बिंदु; यह कुंजी की पीढ़ी को समानांतर करेगा। मेरा मानना ​​है कि इससे प्रमुख पीढ़ी का प्रदर्शन बढ़ेगा। हालाँकि, यदि आप UUID को संग्रहीत करने के लिए VARCHAR का उपयोग करते हैं, तो आप SELECT से अधिक प्रदर्शन का चयन कर रहे हैं। आपको निश्चित रूप से चयन प्रदर्शन को सुनिश्चित करने के लिए भंडारण के लिए वैरिनरी का चयन करना चाहिए। अतिरिक्त चरण INSERT प्रदर्शन को प्रभावित कर सकता है , लेकिन आपको चयन प्रदर्शन में सुधार के साथ भुगतान किया जाएगा।
१०:४० पर Dancrumb

12
हमने वास्तविक डेटा पर कुछ बेंचमार्किंग करना समाप्त कर दिया और GUIDs w / o कुंजियाँ बहुत तेज़ थीं, GUIDs w / कुंजियाँ भयानक थीं (तब भी जब BINARY के रूप में संग्रहीत), और int w / AUTO_COMPLETE सबसे तेज़ था। मुझे लगता है कि हमारे मामले में, हम वास्तव में पेड़ों से जंगल को याद कर रहे थे, क्योंकि अनुक्रम पीढ़ी को अधिक डेटा संग्रहीत करने की लागत की तुलना में असंगत लग रहा था + GUIDs की यादृच्छिकता के कारण वास्तव में भद्दा BTREE होने के कारण
पैट्रिक

1
एक संख्या के रूप में स्टोर करने का मतलब है द्विआधारी प्रारूप में भंडारण? लेकिन बाइनरी प्रारूप मानव के लिए अपठनीय है। यह धीमा है क्योंकि uuid प्राथमिक कुंजी के बड़े बाइट्स? यदि यह है, तो मैं uuid के लिए एक और कॉलम के साथ ऑटो-इन्क्रीमेंट स्टोर कर सकता था। फिर, प्रदर्शन को नुकसान नहीं होगा। क्या मैं सही हू?
चमनप

4
सख्ती से बोलना, यूयूआईडी सार्वभौमिक रूप से अद्वितीय है, जिसका अर्थ है कि यह दुनिया में कहीं और कभी नहीं दिखाई देगा। आपको इसकी आवश्यकता तभी है जब आप अपने डेटा को सार्वजनिक रूप से साझा कर रहे हों। UUID को एक संख्या के रूप में संग्रहीत करने के लिए, मेरा मतलब binaryप्रारूप में नहीं है । मेरा मतलब है 288 बिट स्ट्रिंग के बजाय 128 बिट संख्या। उदाहरण के लिए, ASCII में 'हैलो' शब्द है 68 65 6C 6C 6F, जो संख्या 448,378,203,247 है। स्ट्रिंग को स्टोर करने के लिए '68656C6C6F' को 10 बाइट्स की आवश्यकता होती है। संख्या 448,378,203,247 को केवल 5 की आवश्यकता है। सभी में, जब तक आपको वास्तव में UUID में पहले U की आवश्यकता नहीं होती , तब तक आप इससे बेहतर नहीं कर सकतेauto_increment
Dancrumb

1
@ कैमनैप: सुझाव दें कि आप एक स्टैक ओवरफ्लो प्रश्न पूछें: ओ)
डेंक्रम्ब

78

मेरी नौकरी पर, हम यूयूआईडी का उपयोग पीके के रूप में करते हैं। जो मैं आपको अनुभव से बता सकता हूं वह पीके के रूप में उपयोग नहीं है (वैसे भी SQL सर्वर)।

यह उन चीजों में से एक है, जब आपके पास 1000 से कम रिकॉर्ड होते हैं, ठीक है, लेकिन जब आपके पास लाखों हैं, तो यह सबसे खराब चीज है जो आप कर सकते हैं। क्यों? क्योंकि UUID अनुक्रमिक नहीं है, इसलिए हर बार एक नया रिकॉर्ड डाला जाता है MSSQL को रिकॉर्ड सम्मिलित करने के लिए सही पृष्ठ पर जाने की आवश्यकता होती है, और फिर रिकॉर्ड सम्मिलित करें। इसके साथ वास्तव में बदसूरत परिणाम यह है कि पृष्ठ सभी विभिन्न आकारों में समाप्त हो जाते हैं और वे खंडित हो जाते हैं, इसलिए अब हमें समय-विखंडन करना होगा।

जब आप एक ऑटोइन्क्रिमेंट का उपयोग करते हैं, तो MSSQL हमेशा अंतिम पृष्ठ पर जाएगा, और आप समान रूप से आकार के पृष्ठों (सिद्धांत रूप में) के साथ समाप्त होते हैं, इसलिए उन रिकॉर्ड का चयन करने के लिए प्रदर्शन बहुत बेहतर है (क्योंकि INSERTs तालिका या पृष्ठ को ब्लॉक नहीं करेंगे) बहुत लंबा)।

हालांकि, यूयूआईडी को पीके के रूप में उपयोग करने का बड़ा फायदा यह है कि अगर हमारे पास डीबी के क्लस्टर हैं, तो विलय होने पर संघर्ष नहीं होगा।

मैं निम्नलिखित मॉडल की सिफारिश करूंगा: 1. पीके INT पहचान 2. अतिरिक्त कॉलम स्वचालित रूप से यूयूआईडी के रूप में उत्पन्न होता है।

इस तरह, मर्ज प्रक्रिया संभव है (UUID आपकी वास्तविक कुंजी होगी, जबकि PK केवल कुछ अस्थायी होगा जो आपको अच्छा प्रदर्शन देता है)।

नोट: यह सबसे अच्छा समाधान NEWSEQUENTIALID (जैसे मैं टिप्पणियों में कह रहा था) का उपयोग करना है, लेकिन रिफैक्टर के लिए अधिक समय (और इससे भी बदतर, सभी आवेषणों को नियंत्रित नहीं करना) के साथ विरासत ऐप के लिए, यह करना संभव नहीं है। लेकिन वास्तव में 2017 के रूप में, मैं कहूंगा कि यहां सबसे अच्छा समाधान न्यूसेक्शनल है या गाइड कर रहा है। NHibernate के साथ कोम्ब करें।

उम्मीद है की यह मदद करेगा


मैं वास्तव में नहीं जानता कि उन शब्दों का क्या मतलब है, लेकिन तथ्य यह है कि अनुक्रमित को हर महीने रीइंडएक्स करना पड़ता है। यदि आप जो उल्लेख करते हैं वह रीइंडेक्सिंग कार्य को समाप्त करता है, तो मुझे नहीं पता, लेकिन मैं पूछ सकता हूं।
कैट लिम Ruiz

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

4
Sql सर्वर में @KatLimRuiz आप प्रदर्शन के मुद्दे से बचने के लिए NEWSEQUENTIALID () technet.microsoft.com/en-us/library/ms189786.aspx का उपयोग कर सकते हैं
giammin

वास्तव में, लेकिन NEWSEQUENTIALID केवल DEFAULT के रूप में काम करता है। तो आपको अपने पूरे DAL को इसके चारों ओर डिजाइन करने की आवश्यकता है, जो नई परियोजनाओं के लिए ठीक है लेकिन बड़ी विरासत के लिए इतना आसान नहीं है
कैट लिम Ruiz

@KatLimRuiz प्रतिभा। यह एक महान समझौता है
jmgunn87

26

ध्यान में रखने योग्य बात यह है कि एक समय पर ऑटोइन्क्रिमेंट उत्पन्न होते हैं और एक समानांतर समाधान का उपयोग करके हल नहीं किया जा सकता है। UUIDs का उपयोग करने के लिए लड़ाई आखिरकार आप जो हासिल करना चाहते हैं उसके लिए नीचे आते हैं जो आप संभावित रूप से बलिदान करते हैं।

प्रदर्शन पर, संक्षेप में :

एक UUID ऊपर वाले की तरह 36 अक्षर लंबा है, जिसमें डैश भी शामिल है। यदि आप इस VARCHAR (36) को स्टोर करते हैं, तो आप प्रदर्शन की तुलना नाटकीय रूप से कम करने जा रहे हैं। यह आपकी प्राथमिक कुंजी है, आप नहीं चाहते कि यह धीमा हो।

इसके बिट स्तर पर, एक UUID 128 बिट्स है, जिसका अर्थ है कि यह 16 बाइट्स में फिट होगा, ध्यान दें कि यह बहुत मानव पठनीय नहीं है, लेकिन यह भंडारण कम रखेगा, और 32-बिट इंट, या 2 से केवल 4 गुना बड़ा है 64-बिट int से कई गुना बड़ा है। मैं एक वार्बिनरी (16) सैद्धांतिक रूप से उपयोग करूंगा, यह बहुत अधिक ओवरहेड के बिना काम कर सकता है।

मैं निम्नलिखित दो पोस्ट पढ़ने की सलाह देता हूं:

मैं दोनों के बीच बात करता हूं, वे आपके सवाल का जवाब देते हैं।


2
वास्तव में, मैंने इस प्रश्न को पोस्ट करने से पहले उन दोनों लेखों को पढ़ा, और मेरे पास अभी भी यहां एक अच्छा जवाब नहीं था। उदाहरण के लिए, न तो टाइप 1 बनाम टाइप 4 UUIDS के बारे में बात करें :(
पैट्रिक लाइटबॉडी

उचित है कि, मैंने अपना उत्तर एक स्पर्श अपडेट किया। मुझे नहीं लगता कि यह बहुत अधिक अतिरिक्त जानकारी प्रदान करता है।
काइल रोसेन्डो

@ पैट्रिक: आपने अपने प्रश्न में कई अलग-अलग विषय रखे हैं।

1
9 साल बाद, लेकिन यह भी पोस्टर के लिए ध्यान दिया जाना चाहिए कि पूर्णांक आईडी के विपरीत, डेटाबेस से पीढ़ी को पूरी तरह से हटाते हुए, एप्लिकेशन यूयूआईडी को सुरक्षित रूप से उत्पन्न कर सकते हैं। प्रदर्शन अनुकूलन के लिए यूयूआईडी का हेरफेर (टाइमस्टैम्प-आधारित लेकिन संशोधित किया गया है ताकि वे भोलेपन से छांटे जा सकें) एसक्यूएल के अलावा किसी भी भाषा के बारे में केवल आसान नहीं है। सौभाग्य से आज लगभग सभी डेटाबेस (MySQL शामिल) यूयूआईडी प्राथमिक कुंजी को संभालते हैं जो वे इस्तेमाल करते थे।
माइल्स

5

मैं यूयूआईडी से बचने के लिए बस इसलिए जाता हूं क्योंकि यह स्टोर करने के लिए दर्द है और प्राथमिक कुंजी के रूप में उपयोग करने के लिए दर्द है लेकिन फायदे हैं। मुख्य वे UNIQUE हैं।

मैं आमतौर पर समस्या को हल करता हूं और दोहरी कुंजी क्षेत्रों का उपयोग करके UUID से बचता हूं।

COLLECTOR = एक मशीन के लिए आवश्यक अद्वितीय

ID = COLLECTOR द्वारा स्वतः प्राप्त किया गया (auto_inc फ़ील्ड)

यह मुझे दो चीजें प्रदान करता है। एकत्र होने और एक साथ समूहीकृत होने के बाद एक केंद्रीय स्थान में संग्रहीत किए जा रहे डेटा की ऑटो-इंक फ़ील्ड्स की विशिष्टता और विशिष्टता। मुझे यह भी पता है कि डेटा को ब्राउज़ करते समय यह कहां एकत्र किया गया था जो अक्सर मेरी जरूरतों के लिए काफी महत्वपूर्ण है।

मैंने ग्राहकों के लिए अन्य डेटा सेटों से निपटने के दौरान कई मामलों को देखा है, जहां उन्होंने यूयूआईडी का उपयोग करने का निर्णय लिया है, लेकिन फिर भी एक फ़ील्ड है जहां डेटा एकत्र किया गया था जो वास्तव में प्रयास की बर्बादी है। अपनी कुंजी वास्तव में मदद करता है के रूप में बस दो (या अधिक की जरूरत है) क्षेत्रों का उपयोग कर।

मैंने यूयूआईडी का उपयोग करते हुए बहुत सारे प्रदर्शन हिट देखे हैं। उन्हें एक धोखा लगता है ...


3

प्रत्येक प्रविष्टि के लिए केंद्रीय रूप से अद्वितीय कुंजी बनाने के बजाय, व्यक्तिगत सर्वरों के लिए कुंजी के ब्लॉक आवंटित करने के बारे में कैसे? जब वे चाबियों से बाहर निकलते हैं, तो वे एक नए ब्लॉक का अनुरोध कर सकते हैं। फिर आप प्रत्येक डालने के लिए कनेक्ट करके ओवरहेड की समस्या को हल करते हैं।

Keyserver अगले उपलब्ध आईडी को बनाए रखता है

  • सर्वर 1 अनुरोध आईडी ब्लॉक।
  • कीज़रवर रिटर्न (1,1000)
    सर्वर 1 एक 1000 रिकॉर्ड सम्मिलित कर सकता है जब तक कि उसे नए ब्लॉक का अनुरोध करने की आवश्यकता न हो
  • सर्वर 2 अनुक्रमणिका ब्लॉक का अनुरोध करता है।
  • कीवर रिटर्न (1001,2000)
  • आदि...

आप एक अधिक परिष्कृत संस्करण के साथ आ सकते हैं जहां एक सर्वर आवश्यक कुंजी की संख्या का अनुरोध कर सकता है, या अप्रयुक्त ब्लॉकों को की-ओवर में लौटा सकता है, जो तब उपयोग किए गए / अप्रयुक्त ब्लॉकों के नक्शे को बनाए रखने की आवश्यकता होगी।


सिद्धांत में दिलचस्प सुझाव। यह व्यवहार में प्रबंधन के लिए जटिल होगा। एक अधिक व्यावहारिक समाधान शायद विद्वानों द्वारा उत्तर दिया जाएगा।
साइमन ईस्ट

2

मैं प्रत्येक सर्वर को एक संक्रमणीय तरीके से एक संख्यात्मक आईडी निर्दिष्ट करूंगा। फिर, डाला गया प्रत्येक रिकॉर्ड केवल अपने ही काउंटर को इंगित करेगा। ServerID और RecordID का संयोजन अद्वितीय होगा। सर्वरआईडी क्षेत्र को अनुक्रमित किया जा सकता है और सर्वरिड (यदि आवश्यक हो) के आधार पर भविष्य का चयन बेहतर हो सकता है।


2

संक्षिप्त उत्तर यह है कि कई डेटाबेस में प्रदर्शन समस्याएं हैं (विशेष रूप से उच्च INSERT संस्करणों के साथ) उनके अनुक्रमण विधि और UUIDs के बीच संघर्ष के कारण उच्च क्रम बिट्स में जानबूझकर एन्ट्रापी। कई सामान्य हैक हैं:

  • एक अलग सूचकांक प्रकार (जैसे कि MSSQL पर गैर-सूचीबद्ध) चुनें जो इसे बुरा नहीं मानता
  • एंट्रोपी को निचले-क्रम के बिट्स में स्थानांतरित करने के लिए डेटा को मसलन करें (जैसे MySQL पर V1 UUIDs के बाइट्स को पुनः व्यवस्थित करना)
  • UUID को ऑटो-इंक्रीमेंट int प्राथमिक कुंजी के साथ एक द्वितीयक कुंजी बनाएं

... लेकिन ये सभी हैक हैं - और शायद उस पर नाजुक हैं।

सबसे अच्छा जवाब, लेकिन दुर्भाग्य से सबसे धीमी गति से, अपने विक्रेता को अपने उत्पाद को बेहतर बनाने की मांग करना है ताकि यह किसी अन्य प्रकार की तरह प्राथमिक कुंजी के रूप में यूयूआईडी से निपट सके। वे आपको एक सामान्य उपयोग के मामले में हल करने के लिए अपनी विफलता के लिए अपनी खुद की आधी पक्की हैक को रोल करने के लिए मजबूर नहीं करना चाहिए और केवल बढ़ना जारी रखेंगे।


1

यूआईडी के बारे में कुछ हाथ से तैयार किया गया हज़ारों सर्वरों में से प्रत्येक को एक आईडी दें और प्राथमिक कुंजी को ऑटोइंक्रिमेंट, मशीनआईडी की एक कॉम्बो कुंजी बनाएं ???


मैंने इसके बारे में सोचा है और कुछ बेंचमार्क चलाने की आवश्यकता हो सकती है। यहां तक ​​कि टाइमस्टैम्प के साथ संयुक्त 1000 मशीनों में से प्रत्येक पर एक अस्थायी स्थानीय अनुक्रम, पर्याप्त हो सकता है। Ex: machine_id + temp_seq + टाइमस्टैम्प
पैट्रिक लाइटबॉडी

क्या यह संभव है कि हर टाइमस्टैम्प टिक को रीसेट किया जाए। मुझे यकीन नहीं है।
माइंडस्टल्कर

1

चूंकि प्राथमिक कुंजी विकेंद्रीकृत होती है, इसलिए आपके पास वैसे भी एक auto_increment का उपयोग करने का विकल्प नहीं होता है।

यदि आपको दूरस्थ मशीनों की पहचान छिपाने की आवश्यकता नहीं है, तो UUIDs के बजाय टाइप 1 UUIDs का उपयोग करें। वे उत्पन्न करना आसान है और कम से कम डेटाबेस के प्रदर्शन को चोट नहीं पहुंचा सकते हैं।

वही वार्चर (चार, वास्तव में) बनाम बाइनरी के लिए जाता है: यह केवल मामलों में मदद कर सकता है। क्या यह वास्तव में महत्वपूर्ण है, प्रदर्शन में कितना सुधार हुआ है?


0

मुझे एहसास है कि यह सवाल पुराना है लेकिन मैंने अपने शोध में इस पर जोर दिया। चूंकि कई चीजें हुईं (एसएसडी सर्वव्यापी हैं इनोबीडी को अपडेट आदि मिला)।

मेरे शोध में मुझे प्रदर्शन पर यह दिलचस्प पोस्ट मिली :

यह दावा करते हुए कि GUID / UUID इंडेक्स के यादृच्छिकता के कारण पेड़ असंतुलित हो सकते हैं। मारियाडीबी केबी में मैंने पाया कि एक और पोस्ट ने एक समाधान सुझाया है। लेकिन चूंकि नए UUID_TO_BIN इसकी देखभाल करते हैं। यह फ़ंक्शन केवल MySQL (परीक्षण संस्करण 8.0.18) में उपलब्ध है और मारियाडीबी में नहीं (संस्करण 10.4.10)

TL; DR: रूपांतरित / अनुकूलित BINARY (16) मूल्यों के रूप में UUID को संग्रहीत करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.