ไม่ช้าก็เร็ว หลายคนต้องเผชิญกับความจำเป็นในการแก้ไขบางอย่างในบันทึกตาราง ผมมีอยู่แล้ว
ตัวอย่างเช่น บนโต๊ะที่คุณต้องแก้ไขบางอย่าง ทริกเกอร์ชั่วจะหยุดทำงาน 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