ปิดใช้งานข้อ จำกัด และการตรวจสอบตารางทั้งหมดขณะที่กู้คืนดัมพ์


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ก่อนก่อนจะเกิดข้อผิดพลาด

ต่อไปนี้เป็น SSCCE ที่สร้างฐานข้อมูลดังกล่าวซึ่งเมื่อทิ้งด้วย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 ผลิตการถ่ายโอนข้อมูลที่เป็น restorable ใน DB ที่ว่างเปล่า pg_dumppg_dump
dezso

1
@dezso ถูกต้องสิ่งเหล่านี้เป็นความผิดพลาดฉันได้อัปเดตคำถามแล้ว การถ่ายโอนข้อมูลที่น่าเศร้าไม่ได้พักผ่อนในฐานข้อมูลที่ว่างเปล่าเนื่องจากเหตุผลที่ฉันอ้างถึง
Marcus Junius Brutus

คำถามนี้ต้องการรุ่น Postgres ของคุณไม่ดี นี่ควรจะชัดเจนโดยที่ฉันไม่ได้ชี้ให้เห็น
Erwin Brandstetter

@ErwinBrandstetter ฉันสามารถทำซ้ำปัญหาเดียวกันได้ที่ 9.6, ดูbugs.debian.org/cgi-bin/bugreport.cgi?bug=859033สำหรับตัวอย่างอื่น (โลกแห่งความเป็นจริงใหญ่ขึ้นเล็กน้อย MWE)
mirabilos

1
@ mirabilos: ฉันจะบอกว่า: ถ้าคุณใช้ฟังก์ชั่นที่อ้างอิงตารางอื่น ๆ ในCHECKข้อ จำกัด การรับประกันทั้งหมดจะเป็นโมฆะเพราะมันไม่ได้รับการสนับสนุนอย่างเป็นทางการเพียงแค่ยอมรับ แต่การประกาศCHECKข้อ จำกัดNOT VALIDทำให้ฉันใช้ได้ทุกประการ อาจมีหลายมุมที่ฉันไม่เคยสัมผัส ...
Erwin Brandstetter

คำตอบ:


17

ดังนั้นคุณมองขึ้นตารางอื่น ๆ ในข้อ จำกัดCHECK

CHECKข้อ จำกัด ควรจะเรียกใช้การIMMUTABLEตรวจสอบ สิ่งที่ผ่านไปตกลงสำหรับแถวในครั้งเดียวควรผ่านตกลงได้ตลอดเวลา นั่นคือวิธีการCHECKกำหนดข้อ จำกัด ในมาตรฐาน SQL นั่นเป็นเหตุผลสำหรับข้อ จำกัด นี้ ( ต่อเอกสารประกอบ ):

ปัจจุบัน CHECKนิพจน์ไม่สามารถมีเคียวรีย่อยหรืออ้างถึงตัวแปรอื่นที่ไม่ใช่คอลัมน์ของแถวปัจจุบัน

ตอนนี้นิพจน์ในCHECKข้อ จำกัด ได้รับอนุญาตให้ใช้ฟังก์ชั่นแม้กระทั่งฟังก์ชั่นที่ผู้ใช้กำหนด สิ่งเหล่านั้นควรถูก จำกัด ไว้ที่IMMUTABLEฟังก์ชั่น แต่ Postgres ไม่ได้บังคับใช้สิ่งนี้ จากการสนทนาที่เกี่ยวข้องกับ pgsql-hackersเหตุผลหนึ่งคืออนุญาตให้มีการอ้างอิงถึงเวลาปัจจุบันซึ่งไม่ได้เป็นไปIMMUTABLEตามธรรมชาติ

แต่คุณกำลังค้นหาแถวของตารางอื่นซึ่งเป็นการละเมิดวิธีการอย่างสมบูรณ์ CHECKข้อ จำกัด ในการทำงานอย่างสมบูรณ์ ฉันไม่แปลกใจที่pg_dumpล้มเหลวในการจัดหาสิ่งนี้

ย้ายเช็คของคุณในตารางอื่นไปยังทริกเกอร์ (ซึ่งเป็นเครื่องมือที่เหมาะสม) และควรทำงานกับ Postgres เวอร์ชันทันสมัย

PostgreSQL 9.2 หรือใหม่กว่า

ในขณะที่ข้างต้นเป็นจริงสำหรับ Postgres ทุกรุ่นเครื่องมือต่าง ๆ ได้รับการแนะนำกับ Postgres 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ตัวดัดแปลงสำหรับข้อ จำกัด พร้อมใช้งานสำหรับข้อ จำกัด FK ใน v9.1 เท่านั้น แต่สิ่งนี้จะขยายไปถึงCHECKข้อ จำกัด ใน 9.2 ตามเอกสาร:

หากมีการทำเครื่องหมายข้อ จำกัดNOT VALIDการตรวจสอบเริ่มต้นที่มีความยาวที่อาจเกิดขึ้นเพื่อตรวจสอบว่าแถวทั้งหมดในตารางตรงตามข้อ จำกัด ที่ถูกข้ามไป ข้อ จำกัด จะยังคงมีผลบังคับใช้กับส่วนแทรกหรือการอัพเดตที่ตามมา [... ]

ไฟล์การถ่ายโอนข้อมูล postgres ธรรมดาประกอบด้วยสามส่วน "":

  • pre_data
  • data
  • post-data

Postgres 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 ของฉันไม่สามารถทำซ้ำได้ด้วยทริกเกอร์แทนที่จะตรวจสอบ
Marcus Junius Brutus

1
@MarcusJuniusBrutus: เนื่องจากข้อ จำกัด การตรวจสอบได้รับการประเมินสำหรับแถวทั้งหมดที่มีอยู่แล้วในตารางในการสร้างขณะที่ทริกเกอร์จะทำงานเฉพาะกับเหตุการณ์ที่กำหนดไว้เท่านั้น
Erwin Brandstetter

ฉันทำซ้ำตรรกะ schema ที่แน่นอนโดยใช้ทริกเกอร์ การใช้ทริกเกอร์การคืนค่าจะทำได้สำเร็จ แต่ปรากฏว่านี่เป็นเพียงเพราะความจริงที่ว่าการpg_dumpเพิ่มทริกเกอร์ในตอนท้ายของไฟล์ดัมพ์ในขณะที่มันสร้างCHECKs เป็นส่วนหนึ่งของCREATE TABLEคำสั่ง ดังนั้นการคืนค่าอาจประสบความสำเร็จในกรณีตรวจสอบหากpg_dumpเครื่องมือใช้วิธีการที่แตกต่างกัน ฉันไม่เห็นสาเหตุที่ DDL ของฉันเป็น OK หากฉันใช้ทริกเกอร์ แต่ไม่ตกลงถ้าฉันใช้การตรวจสอบเนื่องจากมีการใช้ตรรกะเดียวกันในทั้งสองกรณี (คุณสามารถดูเวอร์ชันของสคริปต์โดยใช้ทริกเกอร์ในคำตอบของฉันเอง)
Marcus Junius Brutus

1
@MarcusJuniusBrutus: หากคุณรู้สึกว่าpg_dumpควรสร้าง DDL ที่แตกต่างกันสำหรับข้อ จำกัด ในการตรวจสอบ (เช่นการเพิ่มทั้งหมดในตอนท้าย) คุณควรโพสต์สิ่งนั้นไปยังรายชื่อผู้รับจดหมาย Postgres เพื่อขอการปรับปรุง แต่ฉันเห็นด้วยกับ Erwin ว่าคุณใช้ข้อ จำกัด การตรวจสอบที่ผิดพลาดสำหรับสิ่งที่ไม่ได้ออกแบบมา ดังนั้นฉันจะไม่คาดหวังว่าคำขอการเปลี่ยนแปลงที่จะดำเนินการในอนาคตอันใกล้ Btw: SSCCE ของคุณจะเป็นแบบอย่างที่ดีขึ้นโดยใช้ foreign key ระหว่างสองตาราง
a_horse_with_no_name

@MarcusJuniusBrutus: มีวิธีแก้ไขปัญหาสำหรับ Postgres 9.2 หรือใหม่กว่า นั่นเป็นสาเหตุที่รุ่น Postgres ของคุณมีความสำคัญ บางทีการอัพเกรดเป็นตัวเลือกสำหรับคุณ Postgres 9.1 กำลังแก่แล้ว ...
Erwin Brandstetter

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คำสั่งดังเช่นในกรณีของการตรวจสอบ) และเพื่อให้การกู้คืนสำเร็จ


ไม่เห็นตัวอย่างใด ๆ ในตัวคุณ
Sam Watkins

1
@ ข้อผิดพลาด SamWatkins คัดลอกวางแก้ไข
Marcus Junius Brutus
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.