डंप को पुनर्स्थापित करते समय सभी बाधाओं और टेबल की जांच को अक्षम करें


19

मैंने अपने PostgreSQL डेटाबेस का एक डंप प्राप्त किया है:

pg_dump -U user-name -d db-name -f dumpfile

जिसके बाद मैं दूसरे डेटाबेस में पुनर्स्थापित करने के लिए आगे बढ़ा:

psql X -U postgres  -d db-name-b -f dumpfile

मेरी समस्या यह है कि डेटाबेस में संदर्भ संबंधी बाधाएं, चेक और ट्रिगर शामिल हैं और इनमें से कुछ (यह विशेष रूप से प्रतीत होता है) पुनर्स्थापना के दौरान विफल हो जाते हैं क्योंकि जानकारी उस आदेश में लोड नहीं होती है जिससे उन चेक को सम्मानित किया जाएगा। उदाहरण के लिए, किसी तालिका में एक पंक्ति सम्मिलित करना उस फ़ंक्शन से जुड़ा हो सकता है CHECKजो plpgsqlयह जांचता है कि क्या स्थिति किसी अन्य असंबंधित तालिका में है। यदि वह बाद वाली तालिका psqlपूर्व के द्वारा लोड नहीं की गई है , तो एक त्रुटि होती है।

निम्नलिखित एक एसएससीसीई है जो ऐसे डेटाबेस का निर्माण करता है जिसे एक बार डंप करने के बाद pg_dumpबहाल नहीं किया जा सकता है:

CREATE OR REPLACE FUNCTION fail_if_b_empty () RETURNS BOOLEAN AS $$
    SELECT EXISTS (SELECT 1 FROM b)
$$ LANGUAGE SQL;

CREATE TABLE IF NOT EXISTS a (
     i              INTEGER                    NOT NULL
);

INSERT INTO a(i) VALUES (0),(1);
CREATE TABLE IF NOT EXISTS b (
    i  INTEGER NOT NULL
);
INSERT INTO b(i) VALUES (0);

ALTER TABLE a ADD CONSTRAINT a_constr_1 CHECK (fail_if_b_empty());

क्या डंप बहाली के दौरान ऐसी सभी बाधाओं को (कमांड लाइन से) निष्क्रिय करने का एक तरीका है और उन्हें फिर से बाद में सक्षम करना है? मैं PostgreSQL 9.1 चला रहा हूं।


मैं सोच रहा हूं, AFAIK के लिए कोई विकल्प -Xऔर -dविकल्प नहीं हैं pg_dumppg_dumpएक डंप है कि पैदा करता है एक खाली डीबी में restorable।
dezso

1
@ सही, ये टाइपो थे, मैंने सवाल अपडेट कर दिया है। डंप उदासी, नहीं है कारणों का हवाला देते हुए मैं कर रहा हूँ की वजह से एक खाली डीबी में restorable।
मार्कस जूनियस ब्रूटस

प्रश्न को पोस्टग्रेज के आपके संस्करण की बुरी तरह से आवश्यकता है। यह स्पष्ट होना चाहिए मेरे बिना इसे इंगित करते हुए।
इरविन ब्रान्डस्टेट्टर

@ErwinBrandstetter मैं 9.6 पर एक ही समस्या को पुन: उत्पन्न कर सकता है, एक और उदाहरण के लिए Bugs.debian.org/cgi-bin/bugreport.cgi?bug=859033 देखें (अधिक वास्तविक दुनिया, थोड़ा बड़ा, MWE)
mirabilos

1
@mirabilos: मैं कहूंगा: यदि आप एक ऐसे फ़ंक्शन का उपयोग करते हैं जो एक CHECKबाधा में अन्य तालिकाओं का संदर्भ देता है , तो सभी गारंटी शून्य हैं, क्योंकि यह आधिकारिक रूप से समर्थित नहीं है, बस सहन किया गया है। लेकिन CHECKअड़चन घोषित करना NOT VALIDमेरे लिए हर लिहाज से काम का रहा। ऐसे कोने के मामले हो सकते हैं, जिन्हें मैंने कभी नहीं छुआ ...
इरविन ब्रांडस्टेटर

जवाबों:


17

तो आप एक CHECKबाधा में अन्य तालिकाओं को देखते हैं

CHECKबाधाओं को IMMUTABLEचेक चलाने के लिए माना जाता है । एक समय में एक पंक्ति के लिए ओके क्या गुजरता है, किसी भी समय ओके पास करना चाहिए । कैसे CHECKSQL मानक में बाधाओं को परिभाषित किया गया है। इस प्रतिबंध का भी यही कारण है ( प्रति प्रलेखन ):

वर्तमान में, CHECKभावों में उपश्रेणियाँ नहीं हो सकती हैं और न ही वर्तमान पंक्ति के स्तंभों के अलावा अन्य चर का संदर्भ दिया जा सकता है।

अब, CHECKबाधाओं में अभिव्यक्तियों को फ़ंक्शन, यहां तक ​​कि उपयोगकर्ता-परिभाषित कार्यों का उपयोग करने की अनुमति है। उन IMMUTABLEकार्यों के लिए प्रतिबंधित किया जाना चाहिए , लेकिन Postgres वर्तमान में इसे लागू नहीं करता है। Pgsql- हैकर्स पर इस संबंधित चर्चा के अनुसार , एक कारण वर्तमान समय के संदर्भों की अनुमति देना है, जो IMMUTABLEप्रकृति द्वारा नहीं है।

लेकिन आप एक और तालिका की पंक्तियों को देख रहे हैं, जो पूरी तरह से उल्लंघन में है कि कैसे CHECKबाधाओं को काम करना चाहिए। मुझे आश्चर्य नहीं है कि इसके pg_dumpलिए प्रदान करने में विफल रहता है।

अपनी जांच को किसी अन्य तालिका में ट्रिगर करें (जो सही उपकरण है), और इसे पोस्टग्रेज के आधुनिक संस्करणों के साथ काम करना चाहिए।

PostgreSQL 9.2 या बाद का

जबकि पोस्टग्रेज के किसी भी संस्करण के लिए उपरोक्त सही है, आपकी स्थिति में मदद करने के लिए पोस्टग्रेज 9.2 के साथ कई उपकरण पेश किए गए हैं:

pg_dump विकल्प --exclude-table-data

एक सरल समाधान यह होगा कि उल्लंघनकारी तालिका के लिए डेटा के बिना db को डंप करें:

--exclude-table-data=my_schema.my_tbl

फिर डंप के अंत में इस तालिका के लिए केवल डेटा संलग्न करें:

--data-only --table=my_schema.my_tbl

लेकिन एक ही मेज पर अन्य बाधाओं के साथ जटिलताओं को सुनिश्चित किया जा सकता है। एक और भी बेहतर समाधान है :

NOT VALID

नहीं है NOT VALIDबाधाओं के लिए संशोधक। केवल v9.1 में एफके बाधा के लिए उपलब्ध है, लेकिन इसे CHECK9.2 में बाधाओं के लिए बढ़ाया गया था । प्रति प्रलेखन:

यदि बाधा को चिह्नित किया गया है NOT VALID, तो यह सत्यापित करने के लिए कि प्रारंभिक-लंबी जाँच करें कि तालिका में सभी पंक्तियाँ संतुष्ट करती हैं कि बाधा को छोड़ दिया गया है। बाधा अभी भी बाद में आवेषण या अद्यतन के खिलाफ लागू किया जाएगा [...]

एक सादे पोस्टग्राउंड डंप फ़ाइल में तीन "अनुभाग" होते हैं:

  • pre_data
  • data
  • post-data

9.2 पोस्टग्रेट्स ने अलग से वर्गों को डंप करने का एक विकल्प भी पेश किया -- section=sectionname, लेकिन यह समस्या को हाथ में लेने में मदद नहीं कर रहा है।

यहाँ वह दिलचस्प है। प्रति प्रलेखन:

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

बोल्ड जोर मेरा।
आप आक्रामक CHECKबाधा को बदल सकते हैं NOT VALID, जो बाधा को post-dataअनुभाग में ले जाती है। ड्रॉप और फिर से बनाएँ:

ALTER TABLE a DROP CONSTRAINT a_constr_1;
ALTER TABLE a ADD  CONSTRAINT a_constr_1 CHECK (fail_if_b_empty()) NOT VALID;

इससे आपकी समस्या का समाधान हो जाना चाहिए। आप उस स्थिति में भी बाधा छोड़ सकते हैं , क्योंकि यह बेहतर रूप से यह दर्शाता है कि यह वास्तव में क्या करता है: नई पंक्तियों की जांच करें, लेकिन मौजूदा डेटा के लिए कोई गारंटी नहीं दें। एक NOT VALIDचेक बाधा के साथ कुछ भी गलत नहीं है । यदि आप चाहें, तो आप इसे बाद में सत्यापित कर सकते हैं:

ALTER TABLE a VALIDATE CONSTRAINT a_constr_1;

लेकिन तब आप यथास्थिति में वापस आ जाते हैं।


मैंने SSCCE के साथ प्रश्न को समृद्ध किया है जो एक डेटाबेस दिखाता है जिसे पुनर्स्थापित नहीं किया जा सकता है। मुझे वही मिल रहा है जो आप कह रहे हैं, हालाँकि मैं यह नहीं देखता कि मेरे SSCCE में प्रदर्शित होने वाली समस्यात्मक स्थिति को भी चेक के बजाय ट्रिगर्स के साथ पुन: प्रस्तुत क्यों नहीं किया जा सकता है।
मार्कस जुनियस ब्रूटस 19

1
@MarcusJuniusBrutus: क्योंकि चेक बाधाओं को उन सभी पंक्तियों के लिए मूल्यांकन किया जाता है जो पहले से ही निर्माण पर तालिका में हैं, जबकि ट्रिगर केवल परिभाषित घटनाओं पर चलते हैं।
इरविन ब्रान्डसेट्टर

मैंने ट्रिगर का उपयोग करके सटीक स्कीमा तर्क को पुन: प्रस्तुत किया। ट्रिगर्स का उपयोग करके, पुनर्स्थापना वास्तव में सफल होती है लेकिन ऐसा प्रतीत होता है कि यह केवल इस तथ्य के कारण है pg_dumpकि डंप फ़ाइल के अंत में ट्रिगर्स जोड़ता है, जबकि यह कमांड के CHECKहिस्से के रूप में एस बनाता है CREATE TABLE। तो पुनर्स्थापना भी चेक केस के लिए सफल हो सकती है यदि pg_dumpउपकरण एक अलग दृष्टिकोण का उपयोग करता है। मैं यह देखने में विफल रहता हूं कि यदि मैं ट्रिगर्स का उपयोग करता हूं तो मेरा डीडीएल ठीक क्यों है, लेकिन ठीक नहीं अगर मैं चेक का उपयोग करता हूं क्योंकि दोनों मामलों में सटीक एक ही तर्क लागू किया जाता है (आप अपने जवाब में ट्रिगर का उपयोग करके स्क्रिप्ट का संस्करण देख सकते हैं)।
मार्कस जुनियस ब्रूटस

1
@MarcusJuniusBrutus: यदि आपको लगता है कि pg_dumpचेक बाधाओं के लिए अलग-अलग डीडीएल उत्पन्न करना चाहिए (जैसे अंत में उन सभी को जोड़ना) तो आपको पोस्टिंग मेलिंग सूची में वृद्धि अनुरोध के रूप में पोस्ट करना चाहिए। लेकिन मैं इरविन से सहमत हूं कि आप कुछ ऐसी चीज़ों के लिए गलत उपयोग कर रहे हैं जिनके लिए उन्हें डिज़ाइन नहीं किया गया था। इसलिए मुझे उम्मीद नहीं है कि निकट भविष्य में परिवर्तन अनुरोध को लागू किया जाएगा। Btw: आपका SSCCE दो तालिकाओं के बीच एक विदेशी कुंजी का उपयोग करके बेहतर ढंग से तैयार किया जाएगा।
a_horse_with_no_name

@MarcusJuniusBrutus: 9.2 या बाद के पोस्टग्रे के समाधान हैं। यही कारण है कि Postgres का आपका संस्करण महत्वपूर्ण है। शायद उन्नयन आपके लिए एक विकल्प है? पोस्टग्रैजेट्स 9.1 वैसे भी उम्र बढ़ने वाला है ...
इरविन ब्रान्डसेट्टर

2

ऐसा लगता है कि यह pg_dumpडंप बनाने के तरीके के कारण है । वास्तविक डंप को देखकर मैंने देखा कि कमांड CHECKके हिस्से के सिंटैक्स का उपयोग करके बाधा डंप फ़ाइल में मौजूद थी CREATE TABLE:

CREATE TABLE a (
    i integer NOT NULL,
    CONSTRAINT a_constr_1 CHECK (fail_if_b_empty())
);      

यह डेटाबेस की बहाली पर विफलता पैदा करता है क्योंकि चेक को टेबल aया टेबल से पहले रखा जाता है, bजिसमें उनका कोई डेटा होता है। हालाँकि, डंप फ़ाइल को संपादित किया जाता है और डंप फ़ाइल CHECKके अंत में इसके बजाय निम्नलिखित सिंटैक्स का उपयोग करके जोड़ा जाता है:

ALTER TABLE a ADD CONSTRAINT a_constr_1 CHECK (fail_if_b_empty()); 

... फिर बहाली में कोई समस्या नहीं है।

TRIGGERनिम्न समान तर्क को निम्न लिपि में उपयोग करके लागू किया जा सकता है :

CREATE OR REPLACE FUNCTION fail_if_b_empty (
    ) RETURNS BOOLEAN AS $$
    SELECT EXISTS (SELECT 1 FROM b)
$$ LANGUAGE SQL;

DROP TABLE IF EXISTS a;

CREATE TABLE IF NOT EXISTS a (
    i   INTEGER   NOT NULL
);

INSERT INTO a(i) VALUES (0),(1);

CREATE TABLE IF NOT EXISTS b (
    i  INTEGER NOT NULL
);

INSERT INTO b(i) VALUES (0);

CREATE TRIGGER tr1 AFTER INSERT OR UPDATE ON a
FOR EACH ROW
EXECUTE PROCEDURE fail_if_b_empty();  

इस मामले में, हालांकि, pg_dumpडंप फ़ाइल के अंत में ट्रिगर (डिफ़ॉल्ट रूप से) बनाता है ( CREATE TABLEऔर चेक के मामले में बयान में नहीं ) और इसलिए बहाली सफल होती है।


अपने उदाहरण में कोई ट्रिगर न देखें
सैम वाटकिंस

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