PostgreSQL में NULL को निर्दिष्ट नहीं करने के क्या परिणाम हैं, जो उन क्षेत्रों के लिए अशक्त नहीं हो सकते?


10

मेरे पास एक एप्लिकेशन है (डेटा पोस्टग्रेक्यूएल में संग्रहीत है), जहां टेबल के अधिकांश फ़ील्ड हमेशा शून्य नहीं होते हैं, लेकिन इन तालिकाओं के लिए स्कीमा इसे लागू नहीं करता है। उदाहरण के लिए इस नकली तालिका को देखें:

CREATE TABLE "tbl" (
    "id" serial,
    "name" varchar(40),
    "num" int,
    "time" timestamp
    PRIMARY KEY ("id"),
    UNIQUE ("id")
);

इसके अलावा name, num, timeस्पष्ट रूप से कहा गया है के रूप में नहीं कर रहे हैं NOT NULL, वास्तव में वे कर रहे हैं, क्योंकि प्रवर्तन आवेदन पक्ष पर होता है।


मेरी भावना यह है कि इसे बदल दिया जाना चाहिए, लेकिन काउंटरपॉइंट यह है कि आवेदन स्तर यह सुनिश्चित करता है कि अशक्त मूल्य यहां प्रकट नहीं हो सकते हैं और कोई अन्य मैन्युअल रूप से तालिका को संशोधित नहीं करता है।

मेरा सवाल है : क्या लाभ (प्रदर्शन, भंडारण, स्थिरता, कुछ और) और कमियां हैं (यह मानते हुए कि मैं पहले से ही सत्यापित करता हूं कि फिलहाल कोई शून्य मौजूद नहीं है, और व्यापार तर्क से कोई शून्य नहीं होना चाहिए) सेटिंग के साथ स्पष्ट NOT NULLबाधा?

हमारे पास एक अच्छी कोड समीक्षा प्रक्रिया और एक यथोचित दस्तावेज है, इसलिए संभावना है कि कुछ नए व्यक्ति कुछ ऐसा करेंगे जो इस बाधा को तोड़ता है वास्तव में परिवर्तन को सही ठहराने के लिए पर्याप्त नहीं है।

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


1
नल और डिस्क स्थान के विचार के लिए यह उत्तर देखें: stackoverflow.com/questions/5008753/… संक्षेप में, यदि आपकी तालिका में 8 से अधिक स्तंभ हैं और कम से कम 1 अशक्त स्तंभ है, तो तालिका को प्रति पंक्ति अधिक बाइट की आवश्यकता होगी यदि सभी कॉलम हैं परिभाषित नहीं शून्य।
ypercube y

1
@ ypercube y: सटीक होने के लिए, नल बिटमैप केवल पंक्ति में प्रति जोड़ा जाता है यदि पंक्ति में एक वास्तविक शून्य मान है: stackoverflow.com/a/7654497/939860 । इसलिए, NOT NULLभंडारण के आकार पर बाधाओं का कोई सीधा प्रभाव नहीं पड़ता है। बेशक, सभी स्तंभ परिभाषित होने के साथ NOT NULL, एक शून्य बिटमैप शुरू करने के लिए नहीं हो सकता है। दूसरी ओर: भंडारण आकार आम तौर पर बहुत छोटा होता है यदि आप वास्तविक मान के बिना कॉलम के लिए "खाली" या डमी मूल्यों के बजाय NULL का उपयोग करते हैं, क्योंकि नल बिटमैप तुलनात्मक रूप से बहुत छोटा है (दुर्लभ किनारे के मामलों को छोड़कर)।
एरविन ब्रैंडस्टैटर

@ErwinBrandstetter मेरा बुरा तब, उस हिस्से को नहीं समझ पाया था। तो ऐसे कॉलम जिनके लिए कोई शून्य मान नहीं है, भंडारण में कोई वास्तविक अंतर नहीं है, चाहे आप उन्हें NULL या NULL के रूप में परिभाषित करें, सही? क्या इंडेक्स स्टोरेज स्पेस के लिए भी ऐसा ही है?
ypercube y

5
"आवेदन स्तर यह सुनिश्चित करता है कि अशक्त मूल्य यहाँ प्रकट नहीं हो सकते हैं" नहीं, यह नहीं है। यह सुनिश्चित कर सकता है कि एक आवेदन नल नहीं डालता है। लेकिन मेरे पास psql (उदाहरण के लिए) है, और मैं आपके आवेदन के बिना जानबूझकर और दुर्घटनावश दोनों नल को सम्मिलित कर सकता हूं।
माइक शेरिल 'कैट रिकॉल'

5
एकमात्र अनुप्रयोग जो यह सुनिश्चित कर सकता है कि तालिका को मैन्युअल रूप से कोई भी संशोधित नहीं करता है वह dbms ही है।
माइक शेरिल 'कैट रिकॉल'

जवाबों:


9

जब एक नया प्रोग्रामर आता है और उस db के खिलाफ एक ऐप लिखना होता है तो क्या होता है? वे नहीं जानते कि क्षेत्र एक्स है होना करने के लिए NOT NULL

एक अन्य कार्यक्रम यह मान सकता है कि सभी फ़ील्ड x NOT NULLप्रदर्शन करने वाले काउंट्स के लिए कह रहे हैं, लेकिन कुछ अब NULLनए प्रोग्राम के कारण हैं, जिससे त्रुटियों को ट्रेस करने के लिए असंगत और कठिन हो जाता है।

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

प्रोग्रामर, एप्लिकेशन, भाषाएं और रूपरेखाएं आती और जाती हैं। डेटा और डेटाबेस लगातार बने रहते हैं। डेटाबेस असंगत, संभावित रूप से गलत डेटा के खिलाफ रक्षा की आपकी अंतिम पंक्ति है।

प्रदर्शन की कीमत पर भी अपने डेटाबेस की अखंडता बाधा प्रवर्तन तंत्र का अधिकतम उपयोग करें । एक धीमी प्रणाली जो सही परिणाम उत्पन्न करती है वह असीम रूप से तेजी से बेहतर होती है जो गलत हो जाती है!


1
IMHO it is always best to enforce data integrity rules as near to the data as possibleयह वास्तव में मेरे द्वारा लिखे गए आंत की भावना के समान है। और यही कारण है कि मैं वास्तविक औचित्य की तलाश कर रहा हूं। हमारे पास जगह और अच्छे दस्तावेज़ीकरण में कोड की समीक्षा है, इसलिए एक नए डेवलपर के बारे में कुछ भी नहीं जानने की चिंताएं बदलाव को सही ठहराने के लिए पर्याप्त नहीं हैं।
साल्वाडोर डाली

4
कोड समीक्षा और अच्छा प्रलेखन आपको (प्रोग्रामिंग या अन्य) त्रुटियों के खिलाफ गारंटी नहीं देता है।
ypercube y

2
और कितने एक प्रलेख में फंसने से पहले प्रलेखन के सभी (या यहां तक ​​कि किसी भी) REAL PROGRAMMERSपढ़ते हैं, जहां वे एक तंग समय सीमा पर हैं?
वेअर

3
मैंने एक बार एक बैंक में एक समीक्षा की थी जिसमें उनके डेटा वेयरहाउस के लिए समान रवैया था। उनके मामले में - कोई संदर्भात्मक अखंडता नहीं। खैर, ऐसा होता है कि पुराने डेटा का 40% कचरा था क्योंकि किसी ने लुकअप टेबल में प्रलेखन और हटाए गए डेटा को नहीं पढ़ा था। आप डेटा अखंडता के साथ कोड समीक्षाओं और प्रलेखन पर भरोसा नहीं करते हैं - आप इसे डेटाबेस में स्पष्ट करते हैं।
टॉमटॉम

5

जैसा कि पहले से ही टिप्पणियों में दूसरों द्वारा उद्धृत किया गया है, NOT NULLआपकी तालिका विनिर्देश में जोड़ने से आपके प्रश्नों के प्रदर्शन (एक अन्य उत्तर में बताए गए बहुत अच्छे पद्धतिगत कारणों के अलावा) में महत्वपूर्ण तरीके से सुधार हो सकता है ।

कारण यह है कि क्वेरी ऑप्टिमाइज़र, यह जानते हुए कि एक कॉलम का NULLमान नहीं हो सकता है, ऐसे मानों के लिए विशेष परीक्षणों को बाहर कर सकता है, जैसे कि NOT INबनाम NOT EXISTSमामले में। आप उदाहरण के लिए इस ब्लॉग को देख सकते हैं , जहाँ यह दिखाया गया है कि NOT NULLकिसी निश्चित क्वेरी के साथ फ़ील्ड घोषित नहीं करना (जब टेबल में हमेशा अशक्त मान होते हैं) तो निष्पादन का समय 500% बढ़ जाता है। परिणाम SQL सर्वर के लिए दिखाया गया है, लेकिन एक समान व्यवहार आपके जैसे अन्य रिलेशनल DBMS में मौजूद हो सकता है (इस तथ्य का उल्लेख नहीं करने के लिए कि आपका डेटाबेस अन्य सिस्टम में पोर्ट किया जा सकता है)। एक सामान्य नियम जिसे आप मान सकते हैं कि जब क्वेरी ऑप्टिमाइज़र के लिए अधिक जानकारी उपलब्ध है, तो अधिक कुशल एक्सेस प्लान तैयार किए जा सकते हैं।


धन्यवाद। यह उस प्रकार का उत्तर है जिसकी मुझे तलाश थी।
साल्वाडोर डाली

5
जिन कॉलमों में कभी NULL नहीं होता है, उन्हें NOT NULLकई कारणों से परिभाषित किया जाना चाहिए, उनके बारे में कोई तर्क नहीं। लेकिन SQL सर्वर के बारे में ब्लॉग का लिंक Postgres के लिए लागू नहीं है और आपके द्वारा उल्लिखित प्रदर्शन के किसी भी प्रभाव को साबित नहीं करता है। यह कहते हुए कि कोई भी नहीं है, लेकिन मैं वास्तविक सबूत देखना पसंद करूंगा ।
इरविन ब्रान्डस्टेट्टर

@ErwinBrandstetter, मेरे पास पोस्टग्रेसीक्यूएल अनुकूलक के बारे में बहुत अधिक एक्सपोज़र था :( कई परीक्षणों के बाद मुझे पोस्टग्रैसीक्यूएल में ब्लॉग में प्रस्तुत नहीं आईएनआर क्वेरी में महत्वपूर्ण अंतर और बिना पूर्ण बाधा के नहीं मिला। इसलिए, मैंने उत्तर बदल दिया। , और आपसे पूछ रहा हूं कि क्या आपको लगता है कि मुझे इसे पूरी तरह से हटा देना चाहिए।
रेनो

नहीं, मुझे नहीं लगता कि इसे हटा दिया जाना चाहिए। इसमें एक के लिए 5 + वोट और कोई डाउनवोट नहीं है।
ypercube y

not inअशक्त स्तंभों के लिए शब्दार्थ अलग है, हालांकि दोनों के बीच की योजना में कुछ अंतर होना चाहिए ?
मार्टिन स्मिथ

2

अंतरिक्ष के निहितार्थ

अंतरिक्ष निहितार्थ @Erwin Brandstetter द्वारा इस पोस्ट में के बारे में बात कर रहे हैं

संक्षेप में, यदि आप अपने डेटाबेस में हैं, तो आप totalColumns - 8निकटतम बाइट (या MAXALIGN) तक एक बिट को बचाएंगे

  1. 8 से अधिक कॉलम
  2. मेज पर सभी कॉलम हैंNOT NULL

प्रदर्शन के निहितार्थ

हालाँकि, @Erwin Brandstetter द्वारा SE पर इस पोस्ट में , उन्होंने कहा

  1. "NULL सेट करने से प्रदर्शन पर प्रति प्रभाव नहीं पड़ता है। चेक के लिए कुछ चक्र - अप्रासंगिक।"
  2. "... वास्तव में डमी मूल्यों के बजाय NULLs का उपयोग करके। डेटा प्रकारों के आधार पर, आप बहुत सारे डिस्क स्थान और रैम को बचा सकते हैं, जिससे गति बढ़ रही है .. सब कुछ।"

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

CREATE TABLE foo (
  a int,
  b int NOT NULL,
  x float,
  y float NOT NULL
);

INSERT INTO foo ( a, b, x, y )
SELECT x, x, x, x
FROM generate_series(1,1E7) AS X(x);

EXPLAIN ANALYZE SELECT 1/a FROM foo;
EXPLAIN ANALYZE SELECT 1/b FROM foo;
EXPLAIN ANALYZE SELECT 1/x FROM foo;
EXPLAIN ANALYZE SELECT 1/y FROM foo;

इसके अलावा मैंने यह देखने के लिए कुछ परीक्षण चलाए कि क्या NULL-indexes कभी तेज़ थे, और मैं ऐसा नहीं कर सकता। आप स्कॉट मार्लो द्वारा इस अजीब उपयोगी थ्रेड को मेलिंग सूचियों पर पा सकते हैं जो 9.1 में क्वेरी प्लानर के बारे में बात करते हैं जो कि विच्छिन्न WHERE क्लॉस पर आंशिक सूचकांक का उपयोग करने में सक्षम है। मैंने निम्नलिखित परीक्षण करके इसका परीक्षण किया

CREATE TABLE foo ( a int );
CREATE TABLE bar ( a int NOT NULL );
INSERT INTO foo
  SELECT null FROM generate_series(1,1e5) AS x
  UNION ALL
  SELECT 10
  UNION ALL
  SELECT null FROM generate_series(1,1e5) AS x
;
INSERT INTO bar
  SELECT 0 FROM generate_series(1,1e5) AS x
  UNION ALL
  SELECT 10
  UNION ALL
  SELECT 0 FROM generate_series(1,1e5) AS x
;

अब मैंने इंडेक्स बनाया,

CREATE INDEX foobar ON foo(a) WHERE a IS NOT NULL;
CREATE INDEX barbar ON bar(a) WHERE a <> 0;

इन दोनों मामलों में प्लानर इंडेक्स का उपयोग करने में सक्षम था, जिसके = 10लिए क्रमशः NULL या 0 की खोज करते समय एक seq स्कैन का उपयोग किया जाता था। दोनों आंशिक सूचकांक एक ही आकार के थे। और, पूर्ण अनुक्रमित (नहीं दिखाया गया) समान आकार थे। उसी कार्यप्रणाली के बाद मैंने एक अनुक्रम के साथ तालिका को लोड किया 1..1e5, और एक शून्य / 0 मान, और एक अन्य अनुक्रम 1..1e5। दोनों विधियाँ पूरी तालिका को शामिल करने वाले सूचकांक के साथ नल / 0 को खोजने में सक्षम थीं।

TLDR; सारांश

मैं अधिकांश प्रदर्शन चिंताओं पर एक तरह से या किसी अन्य चीज को प्रमाणित नहीं कर सकता था जो मुझे लगा कि योजनाकार अपर्याप्तताओं के लिए परीक्षण के लायक थे। राम को बचाने के लिए अशक्त उपयोग करने का लाभ वास्तविक है। नल का उपयोग न करके सहेजा गया डिस्क स्थान नगण्य है, और यह एक NULLABLEस्तंभ के साथ तालिकाओं पर ओवरस्टेटमेंट है , या 8 कॉलम से कम है। उन मामलों में कोई डिस्क स्थान सहेजा नहीं गया है।

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