यह एक विकट समस्या है। लेकिन इसे PostgreSQL 9.0 में पेश किए गए प्रति-कॉलम ट्रिगर और सशर्त ट्रिगर निष्पादन के साथ किया जा सकता है ।
आपको प्रति पंक्ति एक "अपडेटेड" फ़्लैग की आवश्यकता है इस समाधान के लिए। एक boolean
का प्रयोग करें सादगी के लिए एक ही तालिका में कॉलम। लेकिन यह किसी अन्य तालिका में या प्रति लेनदेन एक अस्थायी तालिका में भी हो सकता है।
महंगा पेलोड प्रति पंक्ति एक बार निष्पादित किया जाता है जहां काउंटर को अपडेट किया जाता है (एक बार या कई बार)।
इसे प्रदर्शन . भी करना चाहिए ठीक है, क्योंकि ...
- ... यह रूट पर ट्रिगर्स की कई कॉल्स से बचता है (स्केल वेल)
- ... अतिरिक्त पंक्तियों को नहीं बदलता है (टेबल ब्लोट को छोटा करें)
- ... को महंगे अपवाद प्रबंधन की आवश्यकता नहीं है।
निम्नलिखित पर विचार करें
डेमो
एक अलग स्कीमा x
. के साथ PostgreSQL 9.1 में परीक्षण किया गया परीक्षण वातावरण के रूप में।
टेबल और डमी पंक्तियां
-- DROP SCHEMA x;
CREATE SCHEMA x;
CREATE TABLE x.tbl (
id int
,counter int
,trig_exec_count integer -- for monitoring payload execution.
,updated bool);
यह प्रदर्शित करने के लिए दो पंक्तियाँ डालें कि यह कई पंक्तियों के साथ काम करता है:
INSERT INTO x.tbl VALUES
(1, 0, 0, NULL)
,(2, 0, 0, NULL);
ट्रिगर फ़ंक्शन और ट्रिगर
1.) महंगा पेलोड निष्पादित करें
CREATE OR REPLACE FUNCTION x.trg_upaft_counter_change_1()
RETURNS trigger AS
$BODY$
BEGIN
-- PERFORM some_expensive_procedure(NEW.id);
-- Update trig_exec_count to count execution of expensive payload.
-- Could be in another table, for simplicity, I use the same:
UPDATE x.tbl t
SET trig_exec_count = trig_exec_count + 1
WHERE t.id = NEW.id;
RETURN NULL; -- RETURN value of AFTER trigger is ignored anyway
END;
$BODY$ LANGUAGE plpgsql;
2.) पंक्ति को अद्यतन के रूप में चिह्नित करें।
CREATE OR REPLACE FUNCTION x.trg_upaft_counter_change_2()
RETURNS trigger AS
$BODY$
BEGIN
UPDATE x.tbl
SET updated = TRUE
WHERE id = NEW.id;
RETURN NULL;
END;
$BODY$ LANGUAGE plpgsql;
3.) "अपडेटेड" फ़्लैग रीसेट करें।
CREATE OR REPLACE FUNCTION x.trg_upaft_counter_change_3()
RETURNS trigger AS
$BODY$
BEGIN
UPDATE x.tbl
SET updated = NULL
WHERE id = NEW.id;
RETURN NULL;
END;
$BODY$ LANGUAGE plpgsql;
ट्रिगर नाम प्रासंगिक हैं! उसी घटना के लिए बुलाया जाता है, उन्हें वर्णानुक्रम में निष्पादित किया जाता है।
1.) पेलोड, अगर अभी तक "अपडेट" नहीं हुआ है:
CREATE CONSTRAINT TRIGGER upaft_counter_change_1
AFTER UPDATE OF counter ON x.tbl
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW
WHEN (NEW.updated IS NULL)
EXECUTE PROCEDURE x.trg_upaft_counter_change_1();
2.) पंक्ति को अद्यतन के रूप में फ़्लैग करें, यदि अभी तक "अपडेट" नहीं किया गया है:
CREATE TRIGGER upaft_counter_change_2 -- not deferred!
AFTER UPDATE OF counter ON x.tbl
FOR EACH ROW
WHEN (NEW.updated IS NULL)
EXECUTE PROCEDURE x.trg_upaft_counter_change_2();
3.) ध्वज रीसेट करें। ट्रिगर की स्थिति के कारण कोई अंतहीन लूप नहीं है।
CREATE CONSTRAINT TRIGGER upaft_counter_change_3
AFTER UPDATE OF updated ON x.tbl
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW
WHEN (NEW.updated) --
EXECUTE PROCEDURE x.trg_upaft_counter_change_3();
परीक्षा
UPDATE
चलाएं &SELECT
आस्थगित प्रभाव देखने के लिए अलग से। यदि एक साथ (एक लेन-देन में) निष्पादित किया जाता है तो चयन नया tbl.counter
. दिखाएगा लेकिन पुराना tbl2.trig_exec_count
।
UPDATE x.tbl SET counter = counter + 1;
SELECT * FROM x.tbl;
अब, काउंटर को कई बार अपडेट करें (एक लेनदेन में)। पेलोड केवल एक बार निष्पादित किया जाएगा। वोइला!
UPDATE x.tbl SET counter = counter + 1;
UPDATE x.tbl SET counter = counter + 1;
UPDATE x.tbl SET counter = counter + 1;
UPDATE x.tbl SET counter = counter + 1;
UPDATE x.tbl SET counter = counter + 1;
SELECT * FROM x.tbl;