PostgreSQL Antipatterns: เปลี่ยนข้อมูลโดยไม่ผ่านทริกเกอร์

ไม่ช้าก็เร็ว หลายคนต้องเผชิญกับความจำเป็นในการแก้ไขบางอย่างในบันทึกตาราง ผมมีอยู่แล้ว บอกฉันว่าจะทำอย่างไรให้ดีขึ้นและอย่างไร - เป็นการดีกว่าที่จะไม่ทำ วันนี้ฉันจะพูดถึงแง่มุมที่สองของการอัพเดทจำนวนมาก - เกี่ยวกับทริกเกอร์.

ตัวอย่างเช่น บนโต๊ะที่คุณต้องแก้ไขบางอย่าง ทริกเกอร์ชั่วจะหยุดทำงาน ON UPDATEโอนการเปลี่ยนแปลงทั้งหมดไปยังการรวมบางส่วน และคุณต้องอัปเดตทุกอย่าง (เช่น เริ่มต้นฟิลด์ใหม่) อย่างระมัดระวังเพื่อไม่ให้การรวมเหล่านี้ได้รับผลกระทบ

มาปิดทริกเกอร์กันเถอะ!

BEGIN;
  ALTER TABLE ... DISABLE TRIGGER ...;
  UPDATE ...; -- тут долго-долго
  ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;

ที่จริงนั่นคือทั้งหมด - ทุกอย่างกำลังแขวนอยู่.

เพราะ ALTER TABLE กำหนด การเข้าถึงพิเศษ- ล็อคที่ไม่มีใครวิ่งขนานกันแม้แต่อันเดียว SELECTจะไม่สามารถอ่านอะไรจากตารางได้ นั่นคือ จนกว่าธุรกรรมนี้จะสิ้นสุดลง ทุกคนที่ต้องการแม้กระทั่ง "เพิ่งอ่าน" จะรอ และเราจำได้ว่า UPDATE เรามียาว...

รีบปิดแล้วเปิดใหม่เร็ว ๆ นี้!

BEGIN;
  ALTER TABLE ... DISABLE TRIGGER ...;
COMMIT;

UPDATE ...;

BEGIN;
  ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;

สถานการณ์ดีขึ้นแล้วเวลารอน้อยลงมาก แต่มีเพียงสองปัญหาเท่านั้นที่ทำลายความงามทั้งหมด:

  • ALTER TABLE ตัวเองกำลังรอการดำเนินการอื่น ๆ ทั้งหมดบนโต๊ะรวมถึงการดำเนินการที่ยาวนาน SELECT
  • ในขณะที่ทริกเกอร์ปิดอยู่ "บินผ่าน" การเปลี่ยนแปลงใด ๆ ในตารางไม่ใช่ของเราด้วยซ้ำ และจะไม่เข้าสู่การรวมแม้ว่าควร ปัญหา!

การจัดการตัวแปรเซสชัน

ดังนั้นในเวอร์ชันก่อนหน้า เราสะดุดกับประเด็นพื้นฐาน - เราต้องสอนทริกเกอร์เพื่อแยกแยะการเปลี่ยนแปลง "ของเรา" ในตารางจาก "ไม่ใช่ของเรา" "ของเรา" จะถูกข้ามตามที่เป็นอยู่ แต่ในส่วน "ไม่ใช่ของเรา" จะถูกเรียกใช้ สำหรับสิ่งนี้คุณสามารถใช้ ตัวแปรเซสชัน.

session_replication_role

อ่าน คู่มือ:

กลไกทริกเกอร์ยังได้รับผลกระทบจากตัวแปรการกำหนดค่าอีกด้วย session_replication_role. เปิดใช้งานโดยไม่มีคำแนะนำเพิ่มเติม (ค่าเริ่มต้น) ทริกเกอร์จะเริ่มทำงานเมื่อบทบาทการจำลองเป็น "ต้นทาง" (ค่าเริ่มต้น) หรือ "ในเครื่อง" เปิดใช้งานทริกเกอร์โดยการระบุ ENABLE REPLICAจะทำงานก็ต่อเมื่อ โหมดเซสชันปัจจุบัน - "แบบจำลอง" และเปิดใช้งานทริกเกอร์โดยการระบุ ENABLE ALWAYSจะทำงานโดยไม่คำนึงถึงโหมดการจำลองปัจจุบัน

ฉันจะเน้นเป็นพิเศษว่าการตั้งค่านี้ใช้ไม่ได้กับทั้งหมดพร้อมกัน เช่น ALTER TABLEแต่เฉพาะการเชื่อมต่อพิเศษของเราเท่านั้น โดยรวมแล้ว เพื่อไม่ให้ทริกเกอร์แอปพลิเคชันทำงาน:

SET session_replication_role = replica; -- выключили триггеры
UPDATE ...;
SET session_replication_role = DEFAULT; -- вернули в исходное состояние

สภาพภายในไกปืน

แต่ตัวเลือกด้านบนใช้ได้กับทริกเกอร์ทั้งหมดในคราวเดียว (หรือคุณต้อง "เปลี่ยน" ทริกเกอร์ล่วงหน้าที่คุณไม่ต้องการปิดใช้งาน) และถ้าเราต้องการ "ปิด" หนึ่งทริกเกอร์เฉพาะ?

สิ่งนี้จะช่วยเรา ตัวแปรเซสชัน "ผู้ใช้":

ชื่อพารามิเตอร์ส่วนขยายเขียนดังนี้: ชื่อส่วนขยายตามด้วยจุดแล้วตามด้วยชื่อพารามิเตอร์เอง คล้ายกับชื่อออบเจกต์แบบเต็มใน SQL ตัวอย่างเช่น: plpgsql.variable_conflict
เนื่องจากสามารถตั้งค่าตัวเลือกนอกระบบในกระบวนการที่ไม่โหลดโมดูลส่วนขยายที่เหมาะสมได้ PostgreSQL จึงยอมรับ ค่าสำหรับชื่อใด ๆ ที่มีสององค์ประกอบ.

ขั้นแรก เราทำทริกเกอร์ให้เสร็จดังนี้:

BEGIN
    -- процессу конвертации можно делать все
    IF current_setting('mycfg.my_table_convert_process') = 'TRUE' THEN
        IF TG_OP IN ('INSERT', 'UPDATE') THEN
            RETURN NEW;
        ELSE
            RETURN OLD;
        END IF;
    END IF;
...

โดยวิธีการนี้สามารถทำได้ "เพื่อผลกำไร" โดยไม่มีการปิดกั้น CREATE OR REPLACE สำหรับฟังก์ชั่นทริกเกอร์ จากนั้นในการเชื่อมต่อพิเศษ เราทดสอบตัวแปร "ของเรา":


SET mycfg.my_table_convert_process = 'TRUE';
UPDATE ...;
SET mycfg.my_table_convert_process = ''; -- вернули в исходное состояние

คุณรู้วิธีอื่นหรือไม่? แบ่งปันในความคิดเห็น

ที่มา: will.com

เพิ่มความคิดเห็น