भंडारण IP पते - varchar (45) बनाम varbinary (16)


11

- मैं दो क्षेत्रों के साथ एक तालिका बनाने के लिए जा रहा हूँ IDके रूप में BIGINTऔर IPAddressके रूप में या तो varchar(45)या varbinary(16)। विचार सभी अद्वितीय आईपी पते को संग्रहीत करने और अन्य तालिकाओं में IDवास्तविक के बजाय एक संदर्भ का उपयोग करने के लिए है IP address

आम तौर पर, मैं एक संग्रहीत प्रक्रिया बनाने जा रहा हूं जो IDदिए गए IP addressया (यदि पता नहीं मिला) के लिए रिटर्न दे रहा है तो पता डालें और उत्पन्न वापस करें ID

मैं कई रिकॉर्ड्स की उम्मीद कर रहा हूं (मैं वास्तव में कितने बता सकता हूं), लेकिन मुझे जितनी जल्दी हो सके निष्पादित करने के लिए ऊपर संग्रहीत प्रक्रिया की आवश्यकता है। इसलिए, मैं सोच रहा हूं कि वास्तविक आईपी पते को कैसे संग्रहीत किया जाए - पाठ या बाइट्स प्रारूप में। कौन सा बेहतर होने जा रहा है?

मैं पहले से ही लिखा है SQL CLRआईपी पते बदलने के लिए कार्य स्ट्रिंग और रिवर्स करने के लिए बाइट्स, तो परिवर्तन एक मुद्दा (दोनों के साथ काम नहीं कर रहा है IPv4और IPv6)।

मुझे लगता है कि मुझे खोज को अनुकूलित करने के लिए एक इंडेक्स बनाने की आवश्यकता है, लेकिन मुझे यकीन नहीं है कि मुझे IP addressफ़ील्ड को क्लस्टर इंडेक्स में शामिल करना चाहिए , या एक अलग इंडेक्स बनाने के लिए और किस प्रकार की खोज तेज़ होगी?


2
IPv4 के लिए कम से कम, 4 छोटे चिह्न क्यों नहीं? फिर वे वास्तव में मानव पठनीय हैं और आपको कोई रूपांतरण करने की आवश्यकता नहीं है। आप विशिष्ट प्रकार की खोजों (सटीक मिलान, सबनेट, आदि) का प्रतिनिधित्व करने के लिए सभी प्रकार के निरंतर कम्प्यूटेड कॉलम भी बना सकते हैं।
हारून बर्ट्रेंड

यदि यह मामला केवल IPv4मेरे लिए था तो मुझे लगता है कि मैं पते को INTक्षेत्र कुंजी के रूप में उपयोग और परिवर्तित करूंगा । लेकिन IPv6मुझे दो BIGINTक्षेत्रों का उपयोग करने की आवश्यकता है और मैं एक क्षेत्र में मूल्य संग्रहीत करना पसंद करता हूं - मुझे अधिक प्राकृतिक लगता है।
gotqn

1
फिर भी समझ में नहीं आता कि 4 टाइन के बजाय INT क्यों? समान भंडारण, आसान डिबगिंग, कम बकवास, IMHO। यदि आपके पास दो अलग-अलग प्रकार के अलग-अलग सत्यापन और अर्थ हैं, तो उन्हें एक ही कॉलम का उपयोग करने की आवश्यकता क्यों है? यदि आप यह शर्त लगा रहे हैं कि एकल कॉलम सरल है, तो SQL_VARIANT का उपयोग क्यों न करें, तो आपको किसी भी चीज़ के बारे में चिंता करने की आवश्यकता नहीं है। आप दिनांक और तार और संख्याओं को संग्रहीत कर सकते हैं और हर कोई एक विशाल, बेकार कॉलम में एक बड़ी पार्टी कर सकता है ...
हारून बर्ट्रेंड

आईपी ​​पते कहां से आ रहे हैं? क्या वे कभी मास्क / सबनेट (यानी 10.10.10.1/124) शामिल करेंगे? मैंने देखा है कि यह वेब सर्वर लॉग से आया है और आसानी से BIGINT में ट्रांसलेट नहीं होता है (INT काम नहीं करेगा क्योंकि गणना के लिए अहस्ताक्षरित INT की आवश्यकता होती है, जब तक कि निश्चित रूप से, आप यह मान लेते हैं कि मान 0 को वास्तव में -2.14xxxx बिलियन है)। मुझे लगता है कि सबनेट मास्क बस एक अतिरिक्त टिनिट फील्ड हो सकता है। लेकिन मुझे समझ में आता है कि BIGINT के रूप में स्टोर करना चाहते हैं अगर उन्हें मैच करने के लिए अक्षांश / देशांतर के DB से मिलान करना चाहते हैं। लेकिन जैसा कि आरोन ने उल्लेख किया है, वह एक संगणित संगणित क्षेत्र हो सकता है।
सोलोमन रटज़की

जवाबों:


13

वास्तविक आईपी पते को कैसे संग्रहीत किया जाए - पाठ या बाइट्स प्रारूप में। कौन सा बेहतर होने जा रहा है?

चूंकि "पाठ" यहां संदर्भित है VARCHAR(45)और "बाइट्स" संदर्भित करता है VARBINARY(16), मैं कहूंगा: न तो

निम्नलिखित जानकारी को देखते हुए ( IPv6 पर विकिपीडिया लेख से ):

पता प्रतिनिधित्व
IPv6 पते के 128 बिट्स 16 बिट्स के 8 समूहों में दर्शाए गए हैं। प्रत्येक समूह को 4 हेक्साडेसिमल अंकों के रूप में लिखा जाता है और समूहों को कॉलन (:) द्वारा अलग किया जाता है। पता 2001: 0db8: 0000: 0000: 0000: ff00: 0042: 8329 इस प्रतिनिधित्व का एक उदाहरण है।

सुविधा के लिए, एक IPv6 पते को निम्नलिखित नियमों के अनुप्रयोग द्वारा संक्षिप्त अधिसूचना में संक्षिप्त किया जा सकता है, जहां संभव हो।

  • हेक्साडेसिमल अंकों के किसी भी समूह से एक या अधिक अग्रणी शून्य हटा दिए जाते हैं; यह आमतौर पर या तो सभी या अग्रणी शून्य में से किसी एक के लिए किया जाता है। उदाहरण के लिए, समूह 0042 को 42 में परिवर्तित किया जाता है।
  • शून्य के लगातार वर्गों को एक दोहरे बृहदान्त्र के साथ बदल दिया जाता है: (:)। डबल कॉलन का उपयोग केवल एक पते में एक बार किया जा सकता है, क्योंकि कई उपयोग पते को अनिश्चित निर्धारित करते हैं। RFC 5952 की सिफारिश है कि शून्य से एक एकल खंड को निरूपित करने के लिए एक दोहरे बृहदान्त्र का उपयोग नहीं किया जाना चाहिए। [41]

इन नियमों के आवेदन का एक उदाहरण:

        प्रारंभिक पता: 2001: 0db8: 0000: 0000: 0000: ff00: 0042: 8329
        प्रत्येक समूह में सभी प्रमुख शून्य निकालने के बाद: 2001: db8: 0: 0: 0: 0 ff00: 42: 8329
        शून्य के लगातार वर्गों को छोड़ने के बाद: 2001 : db8 :: ff00: 42: 8329

मैं VARBINARY(2)8 समूहों का प्रतिनिधित्व करने के लिए 8 क्षेत्रों का उपयोग करके शुरू करूंगा । समूह 5 - 8 के लिए फ़ील्ड होना चाहिए NULLक्योंकि उनका उपयोग केवल IPv6 पते के लिए किया जाएगा। समूह 1 - 4 के लिए फ़ील्ड होना चाहिए NOT NULLक्योंकि उनका उपयोग आईपीवी 4 और आईपीवी 6 पते दोनों के लिए किया जाएगा।

प्रत्येक समूह को स्वतंत्र रखने के रूप में (उन्हें या तो एक VARCHAR(45)या VARBINARY(16)दो BIGINTक्षेत्रों में संयोजित करने का विरोध करने पर ) आपको दो मुख्य लाभ मिलते हैं:

  1. किसी विशेष प्रतिनिधित्व में पते को फिर से बनाना बहुत आसान है। अन्यथा, शून्य के लगातार समूहों को बदलने के लिए: (:) :) आपको इसे बाहर पार्स करना होगा। उन्हें अलग रखना सरल IF/ IIF/ CASEकथनों को सुगम बनाने के लिए अनुमति देता है ।
  2. आप ROW COMPRESSIONया तो सक्षम करके IPv6 पतों पर एक टन स्थान बचाएंगे PAGE COMPRESSION। चूँकि दोनों प्रकार के COMPRESSION उन फ़ील्ड्स की अनुमति देंगे जो 0x000 बाइट्स लेने हैं , उन सभी समूहों के शून्य अब आपके लिए कुछ भी खर्च नहीं करेंगे। दूसरी ओर, यदि आप ऊपर (विकिपीडिया उद्धरण में) से उदाहरण पता संग्रहीत करते हैं, तो बीच में सभी शून्य के 3 सेट अपनी पूरी मात्रा में जगह लेंगे (जब तक आप ऐसा नहीं कर रहे थे VARCHAR(45)और कम अंकन के साथ चले गए थे। , लेकिन यह अनुक्रमण के लिए अच्छी तरह से काम नहीं कर सकता है और इसे पूर्ण प्रारूप में फिर से संगठित करने के लिए विशेष पार्सिंग की आवश्यकता होगी, तो चलो मान लेते हैं कि विकल्प नहीं है ;-)।

यदि आपको नेटवर्क पर कब्जा करने की आवश्यकता है, तो TINYINTउस नाम के लिए एक फ़ील्ड बनाएं , उम, [Network]:-)

नेटवर्क मान के बारे में अधिक जानकारी के लिए, यहाँ IPv6 पते पर एक अन्य विकिपीडिया लेख से कुछ जानकारी दी गई है :

नेटवर्क

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

CIDR अंकन में नेटवर्क पता सीमाएँ लिखी जाती हैं। एक नेटवर्क को ब्लॉक में पहले पते (सभी शून्य में समाप्त), एक स्लैश (/), और उपसर्ग के बिट्स में आकार के बराबर एक दशमलव मान द्वारा दर्शाया जाता है। उदाहरण के लिए, 2001 के रूप में लिखा गया नेटवर्क: db8: 1234 :: / 48 पता 2001 से शुरू होता है: db8: 1234: 0000: 0000: 0000: 0000 और 2001 पर समाप्त होता है: db8: 1234: ffff: ffff: ffff: ffff : ffff।

इंटरफ़ेस पते के रूटिंग उपसर्ग को सीधे सीआईडीआर संकेतन द्वारा पते के साथ संकेत दिया जा सकता है। उदाहरण के लिए, पता 2001: db8: a :: 123, जो सबनेट 2001 से जुड़ा है: db8: a: / 64, 2001 के रूप में लिखा गया है: db8: a :: 123/64।


अनुक्रमण के लिए, मैं कहूंगा कि 8 समूह क्षेत्रों पर एक गैर-संकुल सूचकांक बनाएँ, और संभवतः नेटवर्क क्षेत्र यदि आप इसे शामिल करने का निर्णय लेते हैं।


अंतिम परिणाम निम्न जैसा होना चाहिए:

CREATE TABLE [IPAddress]
(
  IPAddressID INT          NOT NULL IDENTITY(-2147483648, 1),
  Group8      VARBINARY(2) NULL, -- IPv6 only, NULL for IPv4
  Group7      VARBINARY(2) NULL, -- IPv6 only, NULL for IPv4
  Group6      VARBINARY(2) NULL, -- IPv6 only, NULL for IPv4
  Group5      VARBINARY(2) NULL, -- IPv6 only, NULL for IPv4
  Group4      VARBINARY(2) NOT NULL, -- both
  Group3      VARBINARY(2) NOT NULL, -- both
  Group2      VARBINARY(2) NOT NULL, -- both
  Group1      VARBINARY(2) NOT NULL, -- both
  Network     TINYINT      NULL
);

ALTER TABLE [IPAddress]
  ADD CONSTRAINT [PK_IPAddress]
  PRIMARY KEY CLUSTERED
  (IPAddressID ASC)
  WITH (FILLFACTOR = 100, DATA_COMPRESSION = PAGE);

CREATE NONCLUSTERED INDEX [IX_IPAddress_Groups]
  ON [IPAddress] (Group1 ASC, Group2 ASC, Group3 ASC, Group4 ASC,
         Group5 ASC, Group6 ASC, Group7 ASC, Group8 ASC, Network ASC)
  WITH (FILLFACTOR = 100, DATA_COMPRESSION = PAGE);

टिप्पणियाँ:

  • मैं BIGINTमानता हूं कि आप आईडी फ़ील्ड का उपयोग करने की योजना बना रहे हैं , लेकिन क्या आप वास्तव में 4,294,967,295 से अधिक विशिष्ट मूल्यों को पकड़ने की उम्मीद करते हैं? यदि ऐसा है तो बस फ़ील्ड को BIGINT में बदल दें और आप बीज मान को बदलकर 0. भी कर सकते हैं। लेकिन अन्यथा आप INT का उपयोग करना और न्यूनतम मूल्य के साथ शुरू करना बेहतर है ताकि आप उस डेटाटाइप की पूरी रेंज का उपयोग कर सकें ।
  • यदि वांछित है, तो आप IPadddress के पाठ अभ्यावेदन को वापस करने के लिए इस तालिका में एक या एक से अधिक गैर-संगणित कॉलम जोड़ सकते हैं।
  • समूह * फ़ील्ड्स को व्यवस्थित रूप से नीचे की ओर , 8 से 1 तक, तालिका में व्यवस्थित किया जाता है , ताकि ऐसा करने SELECT *से अपेक्षित क्रम में फ़ील्ड वापस आ जाएँ। लेकिन सूचकांक ने उन्हें 1 से 8 तक बढ़ा दिया है , जैसे कि वे कैसे भरे हैं।
  • पाठ रूप में मूल्यों का प्रतिनिधित्व करने के लिए एक गणना स्तंभ का एक उदाहरण (अधूरा) है:

    ALTER TABLE [IPAddress]
      ADD TextAddress AS (
    IIF([Group8] IS NULL,
        -- IPv4
        CONCAT(CONVERT(TINYINT, [Group4]), '.', CONVERT(TINYINT, [Group3]), '.',
          CONVERT(TINYINT, [Group2]), '.', CONVERT(TINYINT, [Group1]),
          IIF([Network] IS NOT NULL, CONCAT('/', [Network]), '')),
        -- IPv6
        LOWER(CONCAT(
          CONVERT(VARCHAR(4), [Group8], 2), ':', CONVERT(VARCHAR(4), [Group7], 2), ':',
          CONVERT(VARCHAR(4), [Group6], 2), ':', CONVERT(VARCHAR(4), [Group5], 2), ':',
          CONVERT(VARCHAR(4), [Group4], 2), ':', CONVERT(VARCHAR(4), [Group3], 2), ':',
          CONVERT(VARCHAR(4), [Group2], 2), ':', CONVERT(VARCHAR(4), [Group1], 2),
          IIF([Network] IS NOT NULL, CONCAT('/', [Network]), '')
         ))
       ) -- end of IIF
    );
    

    परीक्षा:

    INSERT INTO IPAddress VALUES (127, 0, 0, 0, 4, 22, 222, 63, NULL); -- IPv6
    INSERT INTO IPAddress VALUES (27, 10, 1234, 0, 45673, 200, 1, 6363, 48); -- IPv6
    INSERT INTO IPAddress VALUES (NULL, NULL, NULL, NULL, 192, 168, 2, 63, NULL); -- v4
    INSERT INTO IPAddress VALUES (NULL, NULL, NULL, NULL, 192, 168, 137, 29, 16); -- v4
    
    SELECT [IPAddressID], [Group8], [Group1], [Network], [TextAddress]
    FROM IPAddress ORDER BY [IPAddressID];
    

    परिणाम:

    IPAddressID   Group8   Group1   Network  TextAddress
    -----------   ------   ------   -------  ---------------------
    -2147483646   0x007F   0x003F   NULL     007f:0000:0000:0000:0004:0016:00de:003f
    -2147483645   0x001B   0x18DB   48       001b:000a:04d2:0000:b269:00c8:0001:18db/48
    -2147483644   NULL     0x003F   NULL     192.168.2.63
    -2147483643   NULL     0x001D   16       192.168.137.29/16
    

SQL सर्वर 2005 के लिए, के रूप में स्तंभों को परिभाषित करेंगे VARDECIMALसे अधिक VARBINARYके बाद से DATA_COMPRESSIONउपलब्ध नहीं है?
मैट बोर्जा

@SolomonRutzky विस्तृत विवरण के लिए धन्यवाद। मैं उत्सुक हूं, मैं पता श्रेणी के बीच कैसे खोजूंगा? उदाहरण के लिए, मेरे पास प्रारंभ और अंत आईपी पते के रूप में आईपी जियोलोकेशन डेटा प्रदान करने वाला एक डेटा विक्रेता है। मुझे यह खोजने की जरूरत है कि किसी दिए गए आईपी में कौन सी रेंज आती है।
J Weezy

@Jeeeezy आपका स्वागत है :)। प्रारंभ और अंतिम IP पते कैसे संग्रहीत किए जा रहे हैं? क्या आप IPv4 या v6 पतों का उपयोग कर रहे हैं?
सोलोमन रटज़की

@ सोलोमनारटज़की दोनों। IPv4 कोई समस्या नहीं है क्योंकि मैं इसे पूर्णांक के रूप में संग्रहीत कर सकता हूं। दुर्भाग्यवश, SQL सर्वर में कोई 128 बिट पूर्णांक या संख्या से संबंधित डेटा प्रकार नहीं है जो इसे संभालने के लिए पर्याप्त है। इसलिए, IPv6 के लिए मैं इसे VARBINARY (16) में संग्रहीत कर रहा हूं और फिर मैं श्रेणियों की खोज करने के लिए BETWEEN ऑपरेटर का उपयोग करता हूं। लेकिन, मुझे आईपी रेंज पर कई परिणाम मिल रहे हैं, जो मुझे नहीं लगता कि सही हैं। यदि संभव हो तो मैं IPv4 और IPv6 दोनों के लिए एक ही डेटा प्रकार का उपयोग करना चाहूंगा।
J Weezy

@Jeeeezy मैं सुझाव देने जा रहा था BINARY(16);-)। क्या आप मुझे एक शुरुआत / अंतिम सीमा और कम से कम दो पंक्तियों के साथ एक उदाहरण दे सकते हैं जो आपको वापस मिलती हैं, एक वैध और कम से कम एक अमान्य? यह हो सकता है कि VARbinary कुछ मूल्यों को छोटा करता है।
सोलोमन रटज़की

1

छोटा हमेशा तेज होता जा रहा है। छोटे मूल्यों के साथ आप उनमें से अधिक को एक पृष्ठ में फिट कर सकते हैं, इसलिए कम IO, संभावित shallower B-Trees आदि।

अन्य सभी चीजें (अनुवाद ओवरहेड, पठनीयता, अनुकूलता, सीपीयू लोड, इंडेक्स सार्गिबिलिटी आदि) समान हैं, बिल्कुल।

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