SQL Server 2012 में PK GUID अनुक्रमणिका


13

मेरे डेवलपर्स ने अपने सभी तालिकाओं के लिए GUID के पीके के रूप में उपयोग करने के लिए अपने एप्लिकेशन को सेटअप किया है और डिफ़ॉल्ट रूप से SQL सर्वर ने इन PK के पर क्लस्टर किए गए इंडेक्स को सेटअप किया है।

यह प्रणाली अपेक्षाकृत युवा है और हमारी सबसे बड़ी टेबल सिर्फ एक लाख पंक्तियों से अधिक है, लेकिन हम अपनी अनुक्रमणिका पर एक नज़र डाल रहे हैं और निकट भविष्य में इसकी आवश्यकता हो सकती है।

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

क्या इससे क्लस्टरिंग कुंजी बहुत चौड़ी हो जाएगी और क्या यह लिखने के लिए प्रदर्शन को बढ़ावा देगा? रीड्स भी महत्वपूर्ण हैं, लेकिन लिखते हैं कि शायद इस बिंदु पर एक बड़ी चिंता है।


1
GUID कैसे उत्पन्न होते हैं? NEWID या NEWSEQUENTIALID?
स्वस्तिक

6
क्लस्टर किए गए गाइड और इंसर्ट प्रदर्शन केवल एक वाक्य में होने चाहिए, यदि शब्द "प्रदर्शन" से पहले हो तो कम से कम हो
बिलिंक

2
उन डेवलपर्स को दोपहर के भोजन के लिए बाहर ले जाएं और उन्हें समझाएं कि यदि वे प्राथमिक कुंजी के रूप में फिर से न्यूआईडी () का उपयोग करते हैं तो आप उन पर खराब प्रदर्शन को दोषी ठहराएंगे। वे बहुत जल्दी आपसे पूछेंगे कि इसे रोकने के लिए आपको क्या करना चाहिए। किस बिंदु पर, आप कहते हैं कि इसके बजाय पहचान (1,1) का उपयोग करें। (शायद एक मामूली ओवरसिप्लाईफिकेशन लेकिन 10 में से 9 बार यह काम करेगा)।
मैक्स वर्नोन

3
गाइड से हमारी नफरत का कारण यह है कि वे विस्तृत (16 बाइट्स) हैं और जब नहीं बनाए newsequentialidजाते हैं तो यादृच्छिक होते हैं। जब वे संकीर्ण होते हैं और बढ़ते हैं, तो गुच्छेदार कुंजियाँ सबसे अच्छी होती हैं। एक GUID इसके विपरीत है: वसा और यादृच्छिक। किताबों से भरी किताबों की कल्पना कीजिए। OED में आता है और guids की यादृच्छिकता के कारण, यह शेल्फ के बीच में सम्मिलित होता है। चीजों को व्यवस्थित रखने के लिए, सही आधी किताबों को एक नए स्थान पर पहुंचाना होता है, जो एक समय गहन कार्य है। यही GUID आपके डेटाबेस और प्रदर्शन को मार रहा है।
बिलिंक

7
यूनीकॉलीफायर्स का उपयोग करने की समस्या को ठीक करने का तरीका ड्राइंग बोर्ड पर वापस जाना है और यूनीकॉल्डिफायर्स का उपयोग नहीं करना है । यदि सिस्टम छोटा है, तो वे भयानक नहीं हैं , लेकिन यदि आपके पास कम से कम कुछ मिलियन + पंक्ति तालिकाओं (या उस से बड़ी कोई तालिका) है, तो आप कुंजियों के लिए अद्वितीय पहचानकर्ताओं का उपयोग करके कुचलने वाले हैं।
जॉन सेइगल

जवाबों:


20

GUID के साथ प्राथमिक समस्याएं, विशेष रूप से गैर-अनुक्रमिक हैं:

  • कुंजी का आकार (एक बाइट के लिए 16 बाइट्स बनाम एक INT): इसका मतलब है कि आप किसी भी इंडेक्स के लिए उस अतिरिक्त स्थान के साथ-साथ आपकी कुंजी में 4 गुना डेटा संग्रहीत कर रहे हैं यदि यह आपका क्लस्टर इंडेक्स है।
  • सूचकांक विखंडन: मुख्य मूल्यों के पूरी तरह से यादृच्छिक प्रकृति के कारण एक गैर-अनुक्रमिक GUID स्तंभ को डीफ़्रैग्मेन्टेड रखना लगभग असंभव है।

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

GUIDs के आसपास प्राथमिक प्रश्न यह है कि वे कितने आवश्यक हैं। डेवलपर्स उन्हें पसंद करते हैं क्योंकि वे वैश्विक विशिष्टता सुनिश्चित करते हैं, लेकिन यह एक दुर्लभ अवसर है कि इस तरह की विशिष्टता आवश्यक है। लेकिन विचार करें कि यदि आपका अधिकतम मान 2,147,483,647 (4 बाइट हस्ताक्षरित पूर्णांक का अधिकतम मूल्य) से कम है, तो आप शायद अपनी कुंजी के लिए उपयुक्त डेटा प्रकार का उपयोग नहीं कर रहे हैं। BIGINT (8 बाइट्स) का उपयोग करके भी, आपका अधिकतम मूल्य 9,223,372,036,854,775,807 है। यह किसी भी गैर-वैश्विक डेटाबेस (और कई वैश्विक वाले) के लिए आम तौर पर पर्याप्त होता है, अगर आपको एक अद्वितीय कुंजी के लिए कुछ ऑटो-इंक्रीमेंट मूल्य की आवश्यकता होती है।

अंत में, जहाँ तक एक क्लेयर इंडेक्स बनाम ढेर का उपयोग करने की बात है, अगर आप विशुद्ध रूप से डेटा लिख ​​रहे हैं, तो एक ढेर सबसे अधिक कुशल होगा क्योंकि आप आवेषण के लिए ओवरहेड को कम कर रहे हैं। हालाँकि, SQL सर्वर में ढेर डेटा पुनर्प्राप्ति के लिए बेहद अक्षम हैं। मेरा अनुभव रहा है कि यदि आप को एक घोषित करने का अवसर मिला है तो एक क्लस्टर इंडेक्स हमेशा वांछनीय होता है। मैंने एक तालिका (4 बिलियन + रिकॉर्ड) में संकुल सूचकांक के जोड़ को 6 के एक कारक द्वारा समग्र चयन प्रदर्शन में सुधार देखा है।

अतिरिक्त जानकारी:


13

किसी OLTP सिस्टम में कुंजियों और समूहों के रूप में GUID के साथ कुछ भी गलत नहीं है (जब तक कि आपके पास तालिका का अनुक्रमणिका बहुत है जो क्लस्टर के बढ़े हुए आकार से पीड़ित हैं)। तथ्य की बात के रूप में, वे पहचान क्षमता स्तंभों की तुलना में अधिक मापनीय हैं।

व्यापक धारणा है कि SQL सर्वर में GUID एक बड़ी समस्या है - बड़े पैमाने पर, यह काफी सरल रूप से गलत है। तथ्य की बात के रूप में, GUID बॉक्स पर लगभग 8 से अधिक कोर के साथ काफी अधिक स्केलेबल हो सकता है:

मुझे खेद है, लेकिन आपके डेवलपर्स सही हैं। GUID के बारे में चिंता करने से पहले अन्य चीजों के बारे में चिंता करें।

ओह, और अंत में: आप पहले स्थान पर क्लस्टर इंडेक्स क्यों चाहते हैं? यदि आपकी चिंता बहुत छोटे सूचकांक के साथ एक ओएलटीपी प्रणाली है, तो आप एक ढेर के साथ बेहतर होने की संभावना है।

आइए अब विचार करें कि आपके रीड को कौन सा विखंडन (जो GUID पेश करेगा) करता है। विखंडन के साथ तीन प्रमुख समस्याएं हैं:

  1. पृष्ठ विभाजन लागत डिस्क I / O है
  2. आधे पूर्ण पृष्ठ पूर्ण पृष्ठों के समान स्मृति कुशल नहीं हैं
  3. यह पृष्ठों को क्रम से संग्रहीत करने का कारण बनता है, जो क्रमिक I / O कम संभावना बनाता है

चूँकि प्रश्न में आपकी चिंता स्केलेबिलिटी के बारे में है, जिसे हम "अधिक हार्डवेयर जोड़ने से सिस्टम को और तेज़ बनाते हैं" के रूप में परिभाषित कर सकते हैं, ये आपकी समस्याओं में से सबसे कम हैं। बारी-बारी से हर एक को संबोधित करने के लिए

विज्ञापन 1) यदि आप स्केल चाहते हैं, तो आप I / O खरीद सकते हैं। यहां तक ​​कि एक सस्ता सैमसंग / इंटेल 512 जीबी एसएसडी (कुछ अमरीकी डालर / जीबी पर) आपको 100K IOPS से अधिक मिलेगा। आप किसी भी समय 2 सॉकेट सिस्टम पर जल्द ही उपभोग नहीं करेंगे। और अगर आपको इसमें भाग लेना चाहिए, तो एक खरीद लें और आप सेट हो जाएं

विज्ञापन 2) यदि आप अपनी तालिका में हटाते हैं, तो आपके पास वैसे भी पूरे आधे पृष्ठ होंगे। और यहां तक ​​कि अगर तुम नहीं, स्मृति सस्ते और सभी के लिए है, लेकिन सबसे बड़ा OLTP सिस्टम - गर्म डेटा वहाँ फिट होना चाहिए। जब आप पैमाने की तलाश कर रहे हों, तो अधिक डेटा को पृष्ठों में पैक करना उप-अनुकूलन है।

विज्ञापन 3) बार-बार पृष्ठ विभाजन से बनी एक तालिका, अत्यधिक खंडित डेटा यादृच्छिक I / O को ठीक उसी गति से करता है जो क्रमिक रूप से भरी गई तालिका करती है

जुड़ने के संबंध में, दो प्रमुख जॉइन प्रकार हैं जिन्हें आप ओएलटीपी में देख सकते हैं जैसे कार्यभार: हैश और लूप। प्रत्येक को बारी-बारी से देखें:

हैश ज्वाइन करें: एक हैश ज्वाइन करता है कि छोटी टेबल स्कैन की जाती है और बड़ी को आमतौर पर खोजा जाता है। छोटे तालिकाओं की स्मृति में होने की बहुत संभावना है, इसलिए I / O यहां आपकी चिंता नहीं है। हमने पहले से ही इस तथ्य को छुआ था कि खंडित सूचकांक में समान लागत होती है जैसे कि एक गैर खंडित सूचकांक में

लूप जॉइन करें: बाहरी टेबल की तलाश की जाएगी। एक ही लागत

आपके पास बहुत सी खराब टेबल स्कैनिंग हो सकती है - लेकिन फिर GUID फिर से आपकी चिंता नहीं है, उचित अनुक्रमण है।

अब, आपके पास कुछ वैध रेंज स्कैन हो सकते हैं (विशेषकर विदेशी कुंजियों में शामिल होने पर) और इस मामले में, खंडित डेटा गैर-खंडित डेटा की तुलना में कम "पैक" होता है। लेकिन आइए इस पर विचार करें कि 3NF डेटा को अच्छी तरह अनुक्रमित करने के लिए आपको किन चीज़ों को देखने की संभावना होगी:

  1. उस तालिका से जुड़ना, जिसमें उस संदर्भ की तालिका की प्राथमिक कुंजी के लिए एक विदेशी कुंजी संदर्भ है

  2. दूसरी तरह के आसपास

विज्ञापन 1) इस मामले में, आप प्राथमिक कुंजी के लिए एक एकल की तलाश में जा रहे हैं - n में शामिल होने के लिए 1. विखंडन या नहीं, एक ही लागत (एक तलाश)

विज्ञापन 2) इस मामले में, आप एक ही कुंजी में शामिल हो रहे हैं, लेकिन एक से अधिक पंक्ति (रेंज सीक) प्राप्त कर सकते हैं। इस मामले में शामिल 1 से n है। हालाँकि, आप जिस विदेशी तालिका की तलाश कर रहे हैं, आप एसएएमई कुंजी की मांग कर रहे हैं, जो कि खंडित सूचकांक में उसी पृष्ठ पर होने की संभावना है, जो एक खंडित सूचकांक पर है।

एक पल के लिए उन विदेशी कुंजियों पर विचार करें। यहां तक ​​कि अगर आपके पास "पूरी तरह से" अनुक्रमिक हमारी प्राथमिक चाबियाँ रखी गईं - तो उस कुंजी की ओर इशारा करते हुए कुछ भी अभी भी गैर अनुक्रमिक होगा।

बेशक, आप कुछ बैंक में सैन में एक वर्चुअल मशीन पर चल रहे हो सकते हैं जो पैसे पर सस्ता और प्रक्रिया पर उच्च है। फिर यह सब सलाह खो जाएगी। लेकिन अगर वह आपकी दुनिया है, तो मापनीयता वह नहीं है जो आप ढूंढ रहे हैं - आप प्रदर्शन और उच्च गति / लागत की तलाश कर रहे हैं - जो दोनों अलग-अलग चीजें हैं।


1
टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
पॉल व्हाइट 9

5

थॉमस: आपके कुछ बिंदु पूरी तरह से समझ में आते हैं और मैं उन सभी से सहमत हूं। यदि आप SSDs पर हैं, तो आप जो कुछ भी चुनते हैं उसका संतुलन बदलता है। रैंडम बनाम अनुक्रमिक कताई डिस्क के समान चर्चा नहीं है।

मैं विशेष रूप से सहमत हूं कि शुद्ध डीबी दृश्य लेना बहुत ही गलत है। अपने आवेदन को धीमा करने और अस्थिर करने के लिए सिर्फ डीबी प्रदर्शन को काफी गलत समझा जा सकता है।

पहचान (या अनुक्रम, या DB में उत्पन्न कुछ भी ) के साथ बड़ा मुद्दा यह है कि यह बहुत धीमी है क्योंकि इसे कुंजी बनाने के लिए DB की एक गोल यात्रा की आवश्यकता होती है, और यह स्वचालित रूप से आपके DB में एक अड़चन बनाता है, यह इन अनुप्रयोगों को लागू करता है कुंजी का उपयोग शुरू करने के लिए DB कॉल करें। GUID बनाने के लिए कुंजी बनाने के लिए एप्लिकेशन का उपयोग करके इसे हल करता है, यह विश्व स्तर पर अद्वितीय होने की गारंटी देता है (परिभाषा के अनुसार), और एप्लिकेशन परतें इस प्रकार इसका उपयोग डीबी राउंड-ट्रिप के बाद BEFORE के आसपास रिकॉर्ड पास करने के लिए कर सकती हैं।

लेकिन मैं GUIDs के लिए एक विकल्प का उपयोग करने की प्रवृत्ति रखता हूं। यहां डेटाटाइप के लिए मेरी व्यक्तिगत प्राथमिकता ऐप द्वारा उत्पन्न एक विश्व स्तर पर अद्वितीय BIGINT है। यह करने के बारे में कैसे जाना जाता है? सबसे तुच्छ उदाहरण में, आप एक GUID हैश करने के लिए अपने ऐप में एक छोटा, बहुत हल्का कार्य जोड़ते हैं। यह मानते हुए कि आपका हैश फ़ंक्शन तेज़ और अपेक्षाकृत तेज़ है (एक उदाहरण के लिए Google से CityHash देखें: http://google-opensource.blogspot.in/2011/04/introducing-cityhash.html - सुनिश्चित करें कि आपको सभी संकलन सही मिले। या http://tools.ietf.org/html/draft-eastlake-fnv-03 के FNV1a वेरिएंट को सरल कोड के लिए) इससे आपको दोनों विशिष्ट यूनिक आइडेंटिफ़ायर और सीपीयू के साथ बेहतर होने वाले 64 बिट कुंजी मूल्य का लाभ मिलेगा। ।

BIGINTs उत्पन्न करने के अन्य तरीके हैं, और इन दोनों अल्गो में हैश टकराव का एक मौका है - पढ़ें और जागरूक निर्णय लें।


2
मेरा सुझाव है कि आप अपना उत्तर ओपी के प्रश्न के उत्तर के रूप में संपादित करें और थॉमस के उत्तर के उत्तर के रूप में नहीं (जैसा कि अभी है)। आप अभी भी थॉमस (, माइकफाल के) और आपके सुझाव के बीच के अंतर को उजागर कर सकते हैं।
ypercube y

2
कृपया सवाल का जवाब अपने पते पर दें। यदि आप नहीं करते हैं तो हम इसे आपके लिए निकाल देंगे।
JNK

2
टिप्पणी के लिए धन्यवाद मार्क। जब आप अपना उत्तर संपादित करते हैं (जो मुझे लगता है कि कुछ बहुत अच्छा संदर्भ प्रदान करता है) मैं एक बात बदलूंगा: यदि आप INSERT से सावधान हैं, तो IDENTITY सर्वर को अतिरिक्त राउंड ट्रिप की आवश्यकता नहीं है। INSERT को कॉल करने वाले बैच में आप हमेशा SCOPE_IDENTITY () वापस कर सकते हैं
थॉमस केजर

1
के बारे में "यह बहुत धीमी है क्योंकि इसे कुंजी बनाने के लिए DB के लिए एक गोल यात्रा की आवश्यकता होती है" - आप एक दौर की यात्रा में जितनी चाहें उतनी मात्रा में हड़प सकते हैं।
एके

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