मुझे हाल ही में एक SQL सर्वर डेटाबेस विरासत में मिला है जो Guids को स्टोर करने के BINARY(16)
बजाय उपयोग करता है UNIQUEIDENTIFIER
। यह प्राथमिक कुंजियों सहित सब कुछ के लिए करता है।
क्या मुझे चिंतित होना चाहिए?
मुझे हाल ही में एक SQL सर्वर डेटाबेस विरासत में मिला है जो Guids को स्टोर करने के BINARY(16)
बजाय उपयोग करता है UNIQUEIDENTIFIER
। यह प्राथमिक कुंजियों सहित सब कुछ के लिए करता है।
क्या मुझे चिंतित होना चाहिए?
जवाबों:
क्या मुझे चिंतित होना चाहिए?
खैर, यहाँ कुछ चीजें हैं जो थोड़ा संबंधित हैं।
पहला: जबकि यह सच है कि UNIQUEIDENTIFIER
(यानी Guid
) एक 16-बाइट बाइनरी मान है, यह भी सच है कि:
INT
में संग्रहीत किया जा सकता है BINARY(4)
, में संग्रहीत किया DATETIME
जा सकता है BINARY(8)
, आदि), इसलिए # 2 insysname
के लिए एक उपनाम के रूप में NVARCHAR(128)
)।तीन व्यवहारगत अंतर जो मुझे मिल सकते हैं:
UNIQUEIDENTIFIER
SQL सर्वर में मूल्यों की तुलना , बेहतर या बदतर के लिए, वास्तव में BINARY(16)
मूल्यों की तुलना करने के समान नहीं किया जाता है । SQL सर्वर में मानों की तुलना करते समय, GUID और अद्वितीय पहचानकर्ताओं की तुलना करने के लिए MSDN पृष्ठ के अनुसार UNIQUEIDENTIFIER
:
एक मूल्य के अंतिम छह बाइट्स सबसे महत्वपूर्ण हैं
हालांकि इन मूल्यों को अक्सर हल नहीं किया जाता है, इन दो प्रकारों के बीच थोड़ा अंतर है। के लिए MSDN पृष्ठ के अनुसार uniqueidentifier :
आदेश दो मूल्यों के बिट पैटर्न की तुलना करके लागू नहीं किया गया है।
यह देखते हुए कि SQL सर्वर और .NET के बीच GUID मानों को कैसे संभाला जाता है, इस पर मतभेद हैं (ऊपर दिए गए लिंक की तुलना में "GUID और अद्वितीय पहचानकर्ता मान" पृष्ठ में उल्लिखित), इस डेटा को ऐप कोड में SQL सर्वर से खींचना ठीक से निपटा नहीं जा सकता एप्लिकेशन कोड यदि SQL सर्वर तुलना व्यवहार का अनुकरण करने की आवश्यकता है। एक के लिए परिवर्तित करके उस व्यवहार का अनुकरण किया जा सकता है SqlGuid
, लेकिन क्या कोई डेवलपर ऐसा करना जानता होगा?
दूसरा: निम्नलिखित कथन पर आधारित है
यह प्राथमिक कुंजियों सहित सब कुछ के लिए करता है।
मैं सिस्टम के प्रदर्शन के लिए सामान्य रूप से पीके के रूप में INT
या यहां तक BIGINT
कि पीके के रूप में उपयोग करने के साथ वैकल्पिक कुंजी के बजाय पीके के रूप में सिस्टम प्रदर्शन के लिए चिंतित होगा । और इससे भी ज्यादा चिंतित अगर ये GUID PKs क्लस्टर्ड इंडेक्स हैं।
ओपी द्वारा @ रोब के जवाब पर की गई निम्न टिप्पणी एक अतिरिक्त चिंता का विषय है:
मुझे लगता है कि यह MySQL से माइग्रेट किया गया था
GUID को 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
क्या गलत है। और जो हमें तीन सवालों के साथ छोड़ देता है:
आप हमेशा चिंतित रह सकते हैं। ;)
सिस्टम कुछ अन्य सिस्टम से माइग्रेट किया गया हो सकता है जो अद्वितीय पहचानकर्ता का समर्थन नहीं करता है। क्या अन्य समझौते हैं जिनके बारे में आप नहीं जानते हैं?
हो सकता है कि डिज़ाइनर अद्वितीय पहचानकर्ता प्रकार के बारे में नहीं जानता हो। वे किन अन्य चीजों के बारे में नहीं जानते थे?
हालांकि तकनीकी रूप से - यह एक प्रमुख चिंता का विषय नहीं होना चाहिए।