क्या UNIQUEIDENTIFIER के बजाय BINARY (16) का उपयोग करने पर जुर्माना है?


19

मुझे हाल ही में एक SQL सर्वर डेटाबेस विरासत में मिला है जो Guids को स्टोर करने के BINARY(16)बजाय उपयोग करता है UNIQUEIDENTIFIER। यह प्राथमिक कुंजियों सहित सब कुछ के लिए करता है।

क्या मुझे चिंतित होना चाहिए?


क्या यह बाइनरी (16) का लगातार उपयोग करता है? चर और मापदंडों के लिए भी शामिल है? यदि आपको निहित जातियों के प्रभावों पर विचार करने की आवश्यकता नहीं है।
मार्टिन स्मिथ

हां, शुक्र है कि मुझे अंतर्निहित जातियों से भी नहीं निपटना है।
जोनाथन एलन

जवाबों:


21

क्या मुझे चिंतित होना चाहिए?

खैर, यहाँ कुछ चीजें हैं जो थोड़ा संबंधित हैं।

पहला: जबकि यह सच है कि UNIQUEIDENTIFIER(यानी Guid) एक 16-बाइट बाइनरी मान है, यह भी सच है कि:

  1. सभी डेटा को बाइनरी फॉर्म में संग्रहीत किया जा सकता है (जैसे INTमें संग्रहीत किया जा सकता है BINARY(4), में संग्रहीत किया DATETIMEजा सकता है BINARY(8), आदि), इसलिए # 2 in
  2. शायद केवल सुविधा के बाहर GUIDs के लिए एक अलग डेटाटाइप होने का एक कारण है (उदाहरण sysnameके लिए एक उपनाम के रूप में NVARCHAR(128))।

तीन व्यवहारगत अंतर जो मुझे मिल सकते हैं:

  • UNIQUEIDENTIFIERSQL सर्वर में मूल्यों की तुलना , बेहतर या बदतर के लिए, वास्तव में BINARY(16)मूल्यों की तुलना करने के समान नहीं किया जाता है । SQL सर्वर में मानों की तुलना करते समय, GUID और अद्वितीय पहचानकर्ताओं की तुलना करने के लिए MSDN पृष्ठ के अनुसार UNIQUEIDENTIFIER:

    एक मूल्य के अंतिम छह बाइट्स सबसे महत्वपूर्ण हैं

  • हालांकि इन मूल्यों को अक्सर हल नहीं किया जाता है, इन दो प्रकारों के बीच थोड़ा अंतर है। के लिए MSDN पृष्ठ के अनुसार uniqueidentifier :

    आदेश दो मूल्यों के बिट पैटर्न की तुलना करके लागू नहीं किया गया है।

  • यह देखते हुए कि SQL सर्वर और .NET के बीच GUID मानों को कैसे संभाला जाता है, इस पर मतभेद हैं (ऊपर दिए गए लिंक की तुलना में "GUID और अद्वितीय पहचानकर्ता मान" पृष्ठ में उल्लिखित), इस डेटा को ऐप कोड में SQL सर्वर से खींचना ठीक से निपटा नहीं जा सकता एप्लिकेशन कोड यदि SQL सर्वर तुलना व्यवहार का अनुकरण करने की आवश्यकता है। एक के लिए परिवर्तित करके उस व्यवहार का अनुकरण किया जा सकता है SqlGuid, लेकिन क्या कोई डेवलपर ऐसा करना जानता होगा?

दूसरा: निम्नलिखित कथन पर आधारित है

यह प्राथमिक कुंजियों सहित सब कुछ के लिए करता है।

मैं सिस्टम के प्रदर्शन के लिए सामान्य रूप से पीके के रूप में INTया यहां तक BIGINTकि पीके के रूप में उपयोग करने के साथ वैकल्पिक कुंजी के बजाय पीके के रूप में सिस्टम प्रदर्शन के लिए चिंतित होगा । और इससे भी ज्यादा चिंतित अगर ये GUID PKs क्लस्टर्ड इंडेक्स हैं।

अपडेट करें

ओपी द्वारा @ रोब के जवाब पर की गई निम्न टिप्पणी एक अतिरिक्त चिंता का विषय है:

मुझे लगता है कि यह MySQL से माइग्रेट किया गया था

GUID को 2 अलग-अलग बाइनरी प्रारूपों में संग्रहीत किया जा सकता है । तो, वहाँ सकता है चिंता का विषय के आधार पर के लिए कारण हो:

  1. बाइनरी प्रतिनिधित्व किस प्रणाली पर उत्पन्न हुआ था, और
  2. यदि मूल सिस्टम के बाहर स्ट्रिंग मानों का उपयोग किया गया था, जैसे कि ऐप कोड में या क्लाइंट को आयात फ़ाइलों में उपयोग करने के लिए दिया जाता है, आदि।

समस्या जहां बाइनरी प्रतिनिधित्व उत्पन्न किया गया था उसे 4 "फ़ील्ड" में से पहले 3 के बाइट ऑर्डर के साथ करना है। यदि आप विकिपीडिया लेख के ऊपर दिए गए लिंक का अनुसरण करते हैं, तो आप देखेंगे कि RFC 4122 सभी 4 क्षेत्रों के लिए "बिग एंडियन" एन्कोडिंग का उपयोग करने के लिए निर्दिष्ट करता है, फिर भी Microsoft GUID "नेटिव" एंडियननेस का उपयोग करके निर्दिष्ट करते हैं। खैर, इंटेल आर्किटेक्चर लिटिल एंडियन है, इसलिए पहले 3 फ़ील्ड के लिए बाइट ऑर्डर RFC (साथ ही बिग-एंडियन सिस्टम पर उत्पन्न Microsoft-स्टाइल GUID) के बाद के सिस्टम से उलट है। पहला फ़ील्ड, "डेटा 1", 4 बाइट्स है। एक एंडियननेस में इसे (काल्पनिक रूप से) प्रतिनिधित्व किया जाएगा 0x01020304। लेकिन दूसरे एंडियन में यह होगा 0x04030201। तो अगर वर्तमान डेटाबेस 'BINARY(16)उस बाइनरी प्रतिनिधित्व को RFC के बाद एक सिस्टम पर जनरेट किया गया था, फिर वर्तमान में BINARY(16)फ़ील्ड में मौजूद डेटा को एक UNIQUEIDENTIFIERमूल GUID की तुलना में एक अलग GUID में परिवर्तित किया जाएगा। यह वास्तव में एक समस्या पैदा नहीं करता है यदि मानों ने डेटाबेस को कभी नहीं छोड़ा है, और मूल्य केवल समानता के लिए और ऑर्डर नहीं की तुलना में हैं।

आदेश देने के साथ चिंता बस यह है कि वे एक ही क्रम में परिवर्तित करने के बाद नहीं होंगे UNIQUEIDENTIFIER। सौभाग्य से, यदि मूल प्रणाली वास्तव में MySQL थी, तो पहली बार बाइनरी प्रतिनिधित्व पर ऑर्डर करना कभी नहीं था क्योंकि MySQL में केवल UUID का एक स्ट्रिंग प्रतिनिधित्व है ।

डेटाबेस के बाहर उपयोग किए जा रहे स्ट्रिंग मानों के साथ चिंता अधिक गंभीर है, फिर से, यदि विंडोज / एसक्यूएल सर्वर के बाहर द्विआधारी प्रतिनिधित्व उत्पन्न हुआ था। चूंकि बाइट ऑर्डर संभावित रूप से अलग है, तो स्ट्रिंग के रूप में एक ही GUID के परिणामस्वरूप 2 अलग-अलग बाइनरी अभ्यावेदन होंगे, जो उस रूपांतरण पर निर्भर करता है। एप्लिकेशन कोड या ग्राहकों के रूप में स्ट्रिंग रूप में एक GUID दिए गए हैं ABCकी एक बाइनरी रूप से आने वाले 123 और द्विआधारी प्रतिनिधित्व एक प्रणाली पर बनाई गई थी आरएफसी निम्नलिखित है, तो एक ही द्विआधारी प्रतिनिधित्व (यानी कि 123) के एक स्ट्रिंग फार्म के लिए अनुवाद होगा DEFजब करने के लिए परिवर्तित a UNIQUEIDENTIFIER। इसी तरह, मूल स्ट्रिंग के रूप को ABCबाइनरी रूप में 456परिवर्तित किया जाएगा जब एक में परिवर्तित किया जाएगा UNIQUEIDENTIFIER

इसलिए, यदि GUID ने डेटाबेस को कभी नहीं छोड़ा है, तो ऑर्डर करने के बाहर चिंतित होने के लिए बहुत कुछ नहीं है। या, यदि MySQL से आयात स्ट्रिंग रूप (यानी FCCEC3D8-22A0-4C8A-BF35-EC18227C9F40) को परिवर्तित करके किया गया था, तो यह ठीक हो सकता है। इसके अलावा, अगर उन GUID को ग्राहकों को या ऐप कोड में दिया गया था, तो आप यह देखने के लिए परीक्षण कर सकते हैं कि वे कैसे एक को प्राप्त करके परिवर्तित होते हैं SELECT CONVERT(UNIQUEIDENTIFIER, 'value found outside of the database');और यदि आप अपेक्षित रिकॉर्ड पाते हैं तो देखें। यदि आप रिकॉर्ड से मेल नहीं खा सकते हैं, तो आपको खेतों को रखना पड़ सकता है BINARY(16)

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

और वैसे भी नए GUID कैसे डाले जाते हैं? एप्लिकेशन कोड में उत्पन्न?

अद्यतन २

यदि किसी अन्य प्रणाली पर उत्पन्न GUID के द्विआधारी प्रतिनिधित्व को आयात करने से संबंधित संभावित मुद्दे की पिछली व्याख्या थोड़ी (या बहुत) भ्रामक थी, तो उम्मीद है कि निम्नलिखित थोड़ा स्पष्ट होगा:

DECLARE @GUID UNIQUEIDENTIFIER = NEWID();
SELECT @GUID AS [String], CONVERT(BINARY(16), @GUID) AS [Binary];
-- String = 5FED23BE-E52C-40EE-8F45-49664C9472FD
-- Binary = 0xBE23ED5F2CE5EE408F4549664C9472FD
--          BE23ED5F-2CE5-EE40-8F45-49664C9472FD

ऊपर दिखाए गए आउटपुट में, "स्ट्रिंग" और "बाइनरी" मान एक ही GUID से हैं। "बाइनरी" लाइन के नीचे का मूल्य "बाइनरी" लाइन के समान मूल्य है, लेकिन उसी शैली में "स्ट्रिंग" लाइन के रूप में स्वरूपित किया गया है (अर्थात "0x" को हटा दिया गया और चार डैश जोड़े गए)। पहले और तीसरे मूल्यों की तुलना में, वे बिल्कुल समान नहीं हैं , लेकिन वे बहुत करीब हैं: दाएं-सबसे दो खंड समान हैं, लेकिन बाएं-सबसे तीन खंड नहीं हैं। लेकिन अगर आप बारीकी से देखते हैं, तो आप देख सकते हैं कि यह तीनों वर्गों में से प्रत्येक में एक ही बाइट्स है, बस एक अलग क्रम में। यह देखना आसान हो सकता है कि क्या मैं केवल पहले तीन खंडों को दिखाता हूं, और बाइट्स को संख्या देता हूं, इसलिए यह देखना आसान है कि उनका आदेश दो अभ्यावेदन के बीच कैसे भिन्न होता है:

स्ट्रिंग = 1 5F 2 ED 3 23 4 BE - 5 E5 6 2C - 7 40 8 EE
बाइनरी = 4 BE 3 23 2 ED 1 5F - 6 2C 5 E5 - 8 EE 7 40 (विंडोज / एसक्यूएल सर्वर में)

इसलिए प्रत्येक समूह के भीतर, बाइट्स का क्रम उलटा होता है, लेकिन केवल विंडोज और SQL सर्वर के भीतर। हालाँकि, RFC का पालन करने वाली प्रणाली पर, द्विआधारी प्रतिनिधित्व स्टिंग प्रतिनिधित्व को प्रतिबिंबित करेगा क्योंकि बाइट क्रम का कोई भी उलट नहीं होगा।

MySQL से SQL सर्वर में डेटा कैसे लाया गया? यहाँ कुछ विकल्प दिए गए हैं:

SELECT CONVERT(BINARY(16), '5FED23BE-E52C-40EE-8F45-49664C9472FD'),
       CONVERT(BINARY(16), 0x5FED23BEE52C40EE8F4549664C9472FD),
    CONVERT(BINARY(16), CONVERT(UNIQUEIDENTIFIER, '5FED23BE-E52C-40EE-8F45-49664C9472FD'));

यह दिखाता है:

0x35464544323342452D453532432D3430  
0x5FED23BEE52C40EE8F4549664C9472FD  
0xBE23ED5F2CE5EE408F4549664C9472FD

मान लें कि यह सीधे बाइनरी-टू-बाइनरी था (अर्थात # # ऊपर कनवर्ट करें), फिर परिणामस्वरूप GUID, यदि एक वास्तविक में परिवर्तित UNIQUEIDENTIFIERहो जाएगा, तो यह होगा:

SELECT CONVERT(UNIQUEIDENTIFIER, 0x5FED23BEE52C40EE8F4549664C9472FD);

यह दिखाता है:

BE23ED5F-2CE5-EE40-8F45-49664C9472FD

क्या गलत है। और जो हमें तीन सवालों के साथ छोड़ देता है:

  1. SQL सर्वर में डेटा कैसे आयात किया गया था?
  2. ऐप कोड किस भाषा में लिखा जाता है?
  3. ऐप कोड किस प्लेटफ़ॉर्म पर चल रहा है?

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

मैं यह नहीं कह सकता कि मैं बाइट ऑर्डर करने के बारे में स्पष्टीकरण का पूरी तरह से पालन करता हूं, लेकिन यह मुझे अनुक्रमण के बारे में सोचने पर मजबूर कर रहा है। क्या अद्वितीय पहचानकर्ता बाइनरी की तुलना में सूचकांक के विखंडन के परिणामस्वरूप अधिक या कम होगा?
जोनाथन एलन

2
@JonathanAllen मैंने उम्मीद की बेहतर व्याख्या करने के लिए एक और अद्यतन अनुभाग जोड़ा। और नहीं, अनुक्रमण उनके बीच कोई भिन्न नहीं होना चाहिए।
सोलोमन रटज़की

"शुक्र है", SQL सर्वर वेरिएंट 1 और वेरिएंट 2 के बीच ऑर्डरिंग को नहीं बदलता है - भले ही 'डिस्क पर' को अलग तरीके से संग्रहीत किया जा सकता है, यह लगातार भ्रमित करने वाला ऑर्डर है।
user2864740

5

आप हमेशा चिंतित रह सकते हैं। ;)

सिस्टम कुछ अन्य सिस्टम से माइग्रेट किया गया हो सकता है जो अद्वितीय पहचानकर्ता का समर्थन नहीं करता है। क्या अन्य समझौते हैं जिनके बारे में आप नहीं जानते हैं?

हो सकता है कि डिज़ाइनर अद्वितीय पहचानकर्ता प्रकार के बारे में नहीं जानता हो। वे किन अन्य चीजों के बारे में नहीं जानते थे?

हालांकि तकनीकी रूप से - यह एक प्रमुख चिंता का विषय नहीं होना चाहिए।


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