PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

PostgreSQL के लिए कस्टम ट्रिगर आधारित उन्नयन

पहला नियम: आप PostgreSQL को ट्रिगर-आधारित प्रतिकृति के साथ अपग्रेड नहीं करते हैं
दूसरा नियम: आप PostgreSQL को ट्रिगर-आधारित प्रतिकृति के साथ अपग्रेड नहीं करते हैं
तीसरा नियम: यदि आप PostgreSQL को ट्रिगर-आधारित प्रतिकृति के साथ अपग्रेड करते हैं, तो भुगतने के लिए तैयार रहें। और अच्छी तरह से तैयारी करें।

PostgreSQL को अपग्रेड करने के लिए pg_upgrad का उपयोग न करने का एक बहुत ही गंभीर कारण होना चाहिए।

ठीक है, मान लें कि आप डाउनटाइम के सेकंड से अधिक समय नहीं दे सकते। तब pglogic का प्रयोग करें।

ठीक है, मान लीजिए कि आप 9.3 चलाते हैं और इस प्रकार pglogic का उपयोग नहीं कर सकते हैं। लोंडिस्ट का प्रयोग करें।

पढ़ने योग्य रीडमे नहीं मिल रहा है? स्लोनी का प्रयोग करें।

बहुत जटिल? स्ट्रीमिंग प्रतिकृति का उपयोग करें - दास को बढ़ावा दें और उस पर pg_upgrad चलाएं - फिर ऐप्स को नए प्रचारित सर्वर के साथ काम करने के लिए स्विच करें।

आपका ऐप हर समय अपेक्षाकृत लेखन-गहन है? आपने सभी संभावित समाधानों पर ध्यान दिया और अभी भी कस्टम ट्रिगर आधारित प्रतिकृति सेट करना चाहते हैं? तब आपको कुछ बातों पर ध्यान देना चाहिए:

  • सभी तालिकाओं को PK की आवश्यकता होती है। आपको ctid (ऑटोवैक्यूम अक्षम होने पर भी) पर भरोसा नहीं करना चाहिए
  • आपको सभी बाधा बंधित तालिकाओं के लिए ट्रिगर सक्षम करने की आवश्यकता होगी (और आस्थगित FK की आवश्यकता हो सकती है)
  • अनुक्रमों को मैन्युअल रूप से समन्वयित करने की आवश्यकता है
  • अनुमतियों को दोहराया नहीं जाता (जब तक कि आप एक ईवेंट ट्रिगर भी सेट नहीं करते)
  • इवेंट ट्रिगर नई तालिकाओं के लिए समर्थन के स्वचालन में मदद कर सकते हैं, लेकिन पहले से ही जटिल प्रक्रिया को अधिक जटिल नहीं करना बेहतर है। (जैसे तालिका निर्माण पर एक ट्रिगर और एक विदेशी तालिका बनाना, विदेशी सर्वर पर एक ही तालिका बनाना, या एक ही परिवर्तन के साथ दूरस्थ सर्वर तालिका को बदलना, आप पुराने डीबी पर करते हैं)
  • प्रत्येक कथन के लिए ट्रिगर कम विश्वसनीय है लेकिन शायद सरल है
  • आपको अपनी पहले से मौजूद डेटा माइग्रेशन प्रक्रिया की स्पष्ट रूप से कल्पना करनी चाहिए
  • ट्रिगर आधारित प्रतिकृति सेट अप और सक्षम करते समय आपको सीमित टेबल एक्सेसिबिलिटी की योजना बनानी चाहिए
  • इस तरह से जाने से पहले आपको अपने संबंधों की निर्भरता और बाधाओं को पूरी तरह से जान लेना चाहिए।

पर्याप्त चेतावनियाँ? आप पहले से ही खेलना चाहते हैं? आइए फिर कुछ कोड के साथ शुरू करते हैं।

किसी भी ट्रिगर को लिखने से पहले हमें कुछ नकली डेटा सेट बनाना होगा। क्यों? क्या हमारे पास डेटा होने से पहले ट्रिगर करना ज्यादा आसान नहीं होगा? तो डेटा एक ही बार में "अपग्रेड" क्लस्टर में दोहराएगा? ज़रूर होगा। लेकिन फिर हम क्या अपग्रेड करना चाहते हैं? बस एक नए संस्करण पर डेटा सेट बनाएं। तो हाँ, यदि आप एक उच्च संस्करण में अपग्रेड करने की योजना बना रहे हैं और कुछ तालिका जोड़ने की आवश्यकता है, तो डेटा डालने से पहले प्रतिकृति ट्रिगर बनाएं, यह बाद में दोहराए गए डेटा को सिंक करने की आवश्यकता को समाप्त नहीं करेगा। लेकिन ऐसी नई तालिकाएँ, हम कह सकते हैं, एक आसान हिस्सा हैं। तो चलिए पहले मामले का मज़ाक उड़ाते हैं जब हमारे पास अपग्रेड करने का निर्णय लेने से पहले हमारे पास डेटा होता है।

आइए मान लें कि एक पुराने सर्वर को p93 (सबसे पुराना समर्थित) कहा जाता है और जिसे हम दोहराते हैं उसे p10 कहा जाता है (11 इस तिमाही में आने वाला है, लेकिन अभी भी ऐसा नहीं हुआ है):

\c PostgreSQL
select pg_terminate_backend(pid) from pg_stat_activity where datname in ('p93','p10');
drop database if exists p93;
drop database if exists p10;

यहां मैं psql का उपयोग करता हूं, इस प्रकार अन्य डीबी से कनेक्ट करने के लिए \ c मेटा-कमांड का उपयोग कर सकता हूं। यदि आप किसी अन्य क्लाइंट के साथ इस कोड का पालन करना चाहते हैं, तो आपको इसके बजाय फिर से कनेक्ट करना होगा। यदि आप इसे पहली बार चलाते हैं तो निश्चित रूप से आपको इस चरण की आवश्यकता नहीं है। मुझे अपने सैंडबॉक्स को कई बार फिर से बनाना पड़ा, इस प्रकार मैंने बयान सहेजे…

create database p93; --old db (I use 9.3 as oldest supported ATM version)
create database p10; --new db 

इसलिए हम दो नए डेटाबेस बनाते हैं। अब मैं उस से जुड़ूंगा जिसे हम अपग्रेड करना चाहते हैं और कई फंकी डेटा प्रकार बनाएंगे और उनका उपयोग एक तालिका में भरने के लिए करेंगे जिसे हम बाद में पहले से मौजूद मानेंगे:

\c p93
create type myenum as enum('a', 'b');--adding some complex types
create type mycomposit as (a int, b text); --and again...
create table t(i serial not null primary key, ts timestamptz(0) default now(), j json, t text, e myenum, c mycomposit);
insert into t values(0, now(), '{"a":{"aa":[1,3,2]}}', 'foo', 'b', (3,'aloha'));
insert into t (j,e) values ('{"b":null}', 'a');
insert into t (t) select chr(g) from generate_series(100,240) g;--add some more data
delete from t where i > 3 and i < 142; --mockup activity and mix tuples to be not sequential
insert into t (t) select null;

अब हमारे पास क्या है?

  ctid   |  i  |           ts           |          j           |  t  | e |     c     
---------+-----+------------------------+----------------------+-----+---+-----------
 (0,1)   |   0 | 2018-07-08 08:03:00+03 | {"a":{"aa":[1,3,2]}} | foo | b | (3,aloha)
 (0,2)   |   1 | 2018-07-08 08:03:00+03 | {"b":null}           |     | a | 
 (0,3)   |   2 | 2018-07-08 08:03:00+03 |                      | d   |   | 
 (0,4)   |   3 | 2018-07-08 08:03:00+03 |                      | e   |   | 
 (0,143) | 142 | 2018-07-08 08:03:00+03 |                      | ð   |   | 
 (0,144) | 143 | 2018-07-08 08:03:00+03 |                      |     |   | 
(6 rows)

ठीक है, कुछ डेटा - मैंने इतना क्यों डाला और फिर हटा दिया? खैर, हम कुछ समय के लिए मौजूद डेटा सेट का मजाक उड़ाने की कोशिश करते हैं। इसलिए मैं इसे थोड़ा बिखरा हुआ बनाने की कोशिश कर रहा हूं। आइए एक और पंक्ति (0,3) को पृष्ठ के अंत (0,145) पर ले जाएँ:

update t set j = '{}' where i =3; --(0,4)

अब मान लेते हैं कि हम PostgreSQL_fdw का उपयोग करेंगे (यहां dblink का उपयोग करना मूल रूप से समान होगा और संभवत:9.3 के लिए तेज़ होगा, इसलिए यदि आप चाहें तो कृपया ऐसा करें)।

create extension PostgreSQL_fdw;
create server p10 foreign data wrapper PostgreSQL_fdw options (host 'localhost', dbname 'p10'); --I know it's the same 9.3 server - change host to other version and use other cluster if you wish. It's not important for the sandbox...
create user MAPPING FOR vao SERVER p10 options(user 'vao', password 'tsun');

अब हम डीडीएल प्राप्त करने के लिए pg_dump -s का उपयोग कर सकते हैं, लेकिन मेरे पास यह ऊपर है। हमें डेटा को दोहराने के लिए उच्च संस्करण क्लस्टर में एक ही तालिका बनानी होगी:

\c p10
create type myenum as enum('a', 'b');--adding some complex types
create type mycomposit as (a int, b text); --and again...
create table t(i serial not null primary key, ts timestamptz(0) default now(), j json, t text, e myenum, c mycomposit);

अब हम 9.3 पर वापस आते हैं और डेटा माइग्रेशन के लिए विदेशी तालिकाओं का उपयोग करते हैं (मैं f_ . का उपयोग करूंगा यहाँ तालिका नामों के लिए सम्मेलन, f का अर्थ विदेशी है):

\c p93
create foreign table f_t(i serial, ts timestamptz(0) default now(), j json, t text, e myenum, c mycomposit) server p10 options (TABLE_name 't');

आखिरकार! हम एक इन्सर्ट फंक्शन और ट्रिगर बनाते हैं।

create or replace function tgf_i() returns trigger as $$
begin
  execute format('insert into %I select ($1).*','f_'||TG_RELNAME) using NEW;
  return NEW;
end;
$$ language plpgsql;

यहां और बाद में मैं लंबे कोड के लिए लिंक का उपयोग करूंगा। पहला, ताकि स्पोकन टेक्स्ट मशीनी भाषा में न डूबे। दूसरा क्योंकि मैं एक ही फ़ंक्शन के कई संस्करणों का उपयोग यह दर्शाने के लिए करता हूं कि मांग पर कोड कैसे विकसित होना चाहिए।

--OK - first table ready - lets try logical trigger based replication on inserts:
insert into t (t) select 'one';
--and now transactional:
begin;
  insert into t (t) select 'two';
  select ctid, * from f_t;
  select ctid, * from t;
rollback;
select ctid, * from f_t where i > 143;
select ctid, * from t where i > 143;

परिणामी:

INSERT 0 1
BEGIN
INSERT 0 1
 ctid  |  i  |           ts           | j |  t  | e | c 
-------+-----+------------------------+---+-----+---+---
 (0,1) | 144 | 2018-07-08 08:27:15+03 |   | one |   | 
 (0,2) | 145 | 2018-07-08 08:27:15+03 |   | two |   | 
(2 rows)

  ctid   |  i  |           ts           |          j           |  t  | e |     c     
---------+-----+------------------------+----------------------+-----+---+-----------
 (0,1)   |   0 | 2018-07-08 08:27:15+03 | {"a":{"aa":[1,3,2]}} | foo | b | (3,aloha)
 (0,2)   |   1 | 2018-07-08 08:27:15+03 | {"b":null}           |     | a | 
 (0,3)   |   2 | 2018-07-08 08:27:15+03 |                      | d   |   | 
 (0,143) | 142 | 2018-07-08 08:27:15+03 |                      | ð   |   | 
 (0,144) | 143 | 2018-07-08 08:27:15+03 |                      |     |   | 
 (0,145) |   3 | 2018-07-08 08:27:15+03 | {}                   | e   |   | 
 (0,146) | 144 | 2018-07-08 08:27:15+03 |                      | one |   | 
 (0,147) | 145 | 2018-07-08 08:27:15+03 |                      | two |   | 
(8 rows)

ROLLBACK
 ctid  |  i  |           ts           | j |  t  | e | c 
-------+-----+------------------------+---+-----+---+---
 (0,1) | 144 | 2018-07-08 08:27:15+03 |   | one |   | 
(1 row)

  ctid   |  i  |           ts           | j |  t  | e | c 
---------+-----+------------------------+---+-----+---+---
 (0,146) | 144 | 2018-07-08 08:27:15+03 |   | one |   | 
(1 row)

हम यहाँ क्या देखते हैं? हम देखते हैं कि नया डाला गया डेटा सफलतापूर्वक डेटाबेस p10 में दोहराया गया है। और तदनुसार लेन-देन विफल होने पर वापस ले लिया जाता है। अब तक सब ठीक है। लेकिन आप ध्यान नहीं दे सके (हाँ, हाँ - नहीं) कि p93 पर तालिका बहुत बड़ी है - पुराने डेटा को दोहराया नहीं गया। हम इसे वहां कैसे प्राप्त करते हैं? बहुत आसान:

insert into … select local.* from ...outer join foreign where foreign.PK is null 

करेंगे। और यह यहां मुख्य चिंता नहीं है - आपको यह चिंता करनी चाहिए कि आप अपडेट और डिलीट पर पहले से मौजूद डेटा को कैसे प्रबंधित करेंगे - क्योंकि निचले संस्करण डीबी पर सफलतापूर्वक चलने वाले बयान विफल हो जाएंगे या केवल शून्य पंक्तियों को प्रभावित करेंगे - सिर्फ इसलिए कि पहले से मौजूद डेटा नहीं है ! और यहाँ हम डाउनटाइम वाक्यांश के सेकंड में आते हैं। (यदि यह एक फिल्म होती, तो निश्चित रूप से यहां हमारे पास एक फ्लैशबैक होता, लेकिन अफसोस - यदि वाक्यांश "सेकंड ऑफ डाउनटाइम" ने पहले आपका ध्यान आकर्षित नहीं किया, तो आपको ऊपर जाना होगा और वाक्यांश को देखना होगा...)

सभी स्टेटमेंट ट्रिगर्स को सक्षम करने के लिए आपको टेबल को फ्रीज करना होगा, सभी डेटा को कॉपी करना होगा और फिर ट्रिगर्स को सक्षम करना होगा, इसलिए निचले और उच्च संस्करण डेटाबेस पर टेबल सिंक में होंगे और सभी स्टेटमेंट्स में एक जैसा होगा (या बेहद करीब, क्योंकि भौतिक वितरण अलग होगा, फिर से ctid कॉलम के पहले उदाहरण को देखें) प्रभावित करें। लेकिन इस तरह के "प्रतिकृति को चालू करें" को एक बीआईआईआईआईजी लेनदेन में टेबल पर चलाना डाउनटाइम के सेकंड नहीं होगा। संभावित रूप से यह साइट को घंटों के लिए केवल पढ़ने के लिए बना देगा। विशेष रूप से यदि तालिका मोटे तौर पर अन्य बड़ी तालिकाओं के साथ FK द्वारा बंधी हुई है।

वेल रीड ओनली पूर्ण डाउनटाइम नहीं है। लेकिन बाद में हम सभी चयनों और कुछ INSERT, DELETE, UPDATE को काम करने (नए डेटा पर, पुराने पर विफल) छोड़ने का प्रयास करेंगे। तालिका या लेन-देन को केवल पढ़ने के लिए कई तरीकों से किया जा सकता है - क्या यह कुछ पोस्टग्रेएसक्यूएल दृष्टिकोण, या एप्लिकेशन स्तर, या यहां तक ​​​​कि अस्थायी रूप से अनुमतियों के अनुसार रद्द करना होगा। ये दृष्टिकोण स्वयं अपने ब्लॉग के लिए एक विषय हो सकते हैं, इस प्रकार मैं केवल इसका उल्लेख करूंगा।

फिर भी। ट्रिगर्स को लौटें। समान क्रिया करने के लिए, दूरस्थ तालिका पर अलग-अलग पंक्ति (अद्यतन, हटाएं) पर काम करने की आवश्यकता होती है जैसा कि आप स्थानीय पर करते हैं, हमें प्राथमिक कुंजी का उपयोग करने की आवश्यकता होती है, क्योंकि भौतिक स्थान भिन्न होगा। और प्राथमिक कुंजी अलग-अलग स्तंभों के साथ अलग-अलग तालिकाओं पर बनाई जाती हैं, इस प्रकार हमें या तो प्रत्येक तालिका के लिए अद्वितीय फ़ंक्शन बनाना होगा या कुछ सामान्य लिखने का प्रयास करना होगा। आइए (सादगी के लिए) मान लें कि हमारे पास केवल एक कॉलम पीके है, तो इस फ़ंक्शन को मदद करनी चाहिए। तो अंत में! आइए यहां एक अपडेट फ़ंक्शन करें। और जाहिर तौर पर एक ट्रिगर:

create trigger tgu before update on t for each row execute procedure tgf_u();
आज श्वेतपत्र डाउनलोड करें क्लस्टर नियंत्रण के साथ पोस्टग्रेएसक्यूएल प्रबंधन और स्वचालन इस बारे में जानें कि पोस्टग्रेएसक्यूएल को तैनात करने, निगरानी करने, प्रबंधित करने और स्केल करने के लिए आपको क्या जानना चाहिए। श्वेतपत्र डाउनलोड करें

और देखते हैं कि क्या यह काम करता है:

begin;
        update t set j = '{"updated":true}' where i = 144;
        select * from t where i = 144;
        select * from f_t where i = 144;
Rollback;

इसके परिणामस्वरूप:

BEGIN
psql:blog.sql:71: INFO:  (144,"2018-07-08 09:09:20+03","{""updated"":true}",one,,)
UPDATE 1
  i  |           ts           |        j         |  t  | e | c 
-----+------------------------+------------------+-----+---+---
 144 | 2018-07-08 09:09:20+03 | {"updated":true} | one |   | 
(1 row)

  i  |           ts           |        j         |  t  | e | c 
-----+------------------------+------------------+-----+---+---
 144 | 2018-07-08 09:09:20+03 | {"updated":true} | one |   | 
(1 row)

ROLLBACK

ठीक है। और जबकि यह अभी भी गर्म है, आइए डिलीट ट्रिगर फ़ंक्शन और प्रतिकृति को भी जोड़ें:

create trigger tgd before delete on t for each row execute procedure tgf_d();

और जांचें:

begin;
        delete from t where i = 144;
        select * from t where i = 144;
        select * from f_t where i = 144;
Rollback;

देना:

DELETE 1
 i | ts | j | t | e | c 
---+----+---+---+---+---
(0 rows)

 i | ts | j | t | e | c 
---+----+---+---+---+---
(0 rows)

जैसा कि हमें याद है (इसे कौन भूल सकता है!) हम लेन-देन में "प्रतिकृति" समर्थन नहीं बदल रहे हैं। और अगर हमें लगातार डेटा चाहिए तो हमें चाहिए। जैसा कि ऊपर कहा गया है, सभी एफके संबंधित तालिकाओं पर सभी स्टेटमेंट ट्रिगर्स को एक लेनदेन में सक्षम किया जाना चाहिए, जो पहले डेटा को सिंक करके तैयार किया गया था। अन्यथा हम इसमें पड़ सकते हैं:

begin;
        select * from t where i = 3;
        delete from t where i = 3;
        select * from t where i = 3;
        select * from f_t where i = 3;
Rollback;

देना:

p93=# begin;
BEGIN
p93=#         select * from t where i = 3;
 i |           ts           | j  | t | e | c 
---+------------------------+----+---+---+---
 3 | 2018-07-08 09:16:27+03 | {} | e |   | 
(1 row)

p93=#         delete from t where i = 3;
DELETE 1
p93=#         select * from t where i = 3;
 i | ts | j | t | e | c 
---+----+---+---+---+---
(0 rows)

p93=#         select * from f_t where i = 3;
 i | ts | j | t | e | c 
---+----+---+---+---+---
(0 rows)

p93=# rollback;

याकी! हमने निचले संस्करण डीबी पर एक पंक्ति हटा दी है और नए पर नहीं! सिर्फ इसलिए कि यह वहां नहीं था। ऐसा नहीं होगा अगर हमने इसे सही तरीके से किया (शुरू; सिंक; ट्रिगर सक्षम करें; अंत;)। लेकिन सही तरीका टेबल को लंबे समय तक केवल पढ़ने के लिए बना देगा! सबसे कट्टर पाठक यह भी कहेंगे कि 'तब आप ट्रिगर आधारित प्रतिकृति क्यों करेंगे?'।

आप इसे "सामान्य" लोगों के रूप में pg_upgrad के साथ कर सकते हैं। और स्ट्रीमिंग प्रतिकृति के मामले में आप सभी सेट को केवल पढ़ने के लिए बना सकते हैं। एक्सलॉग रीप्ले को रोकें और मास्टर को अपग्रेड करें जबकि एप्लिकेशन अभी भी आरओ गुलाम है।

बिल्कुल! क्या मैंने इसकी शुरुआत नहीं की थी?

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

तो आप कुछ ऑनलाइन एटीएम काम करने वाले लोगों को छोड़ देते हैं, नए लोगों को बिना यह देखे भी काम करने देते हैं कि आप अपग्रेड के बीच में हैं। भयानक लगता है, लेकिन क्या मैंने काल्पनिक रूप से नहीं कहा? मैंने नहीं किया? खैर, मेरा मतलब था।

कोई फर्क नहीं पड़ता कि वास्तविक जीवन का मामला क्या हो सकता है, आइए देखें कि आप इसे कैसे लागू कर सकते हैं। डिलीट और अपडेट फंक्शन बदल जाएंगे। और अब अंतिम परिदृश्य देखें:

BEGIN
psql:blog.sql:86: ERROR:  This data is not replicated yet, thus can't be deleted
psql:blog.sql:87: ERROR:  current transaction is aborted, commands ignored until end of transaction block
psql:blog.sql:88: ERROR:  current transaction is aborted, commands ignored until end of transaction block
ROLLBACK

निचले संस्करण पर पंक्ति को हटाया नहीं गया था, क्योंकि यह उच्च संस्करण पर नहीं मिला था। अपडेट के साथ भी ऐसा ही होगा। इसे स्वयं आज़माएं। अब आप ट्रिगर आधारित प्रतिकृति में शामिल तालिका में अधिक संशोधनों को रोके बिना डेटा समन्वयन प्रारंभ कर सकते हैं।

क्या यह बेहतर है? बदतर? यह अलग है - वैश्विक आरओ सिस्टम पर इसमें कई खामियां और कुछ लाभ हैं। मेरा लक्ष्य यह प्रदर्शित कर रहा था कि कोई व्यक्ति सामान्य से अधिक इस तरह की जटिल पद्धति का उपयोग क्यों करना चाहेगा - एक स्थिर, प्रसिद्ध प्रक्रिया पर विशिष्ट क्षमता प्राप्त करने के लिए। बेशक किसी कीमत पर…

इसलिए, अब जब हम डेटा स्थिरता के लिए थोड़ा सुरक्षित महसूस करते हैं और तालिका t में हमारा पहले से मौजूद डेटा p10 के साथ समन्वयित हो रहा है, तो हम अन्य तालिकाओं के बारे में बात कर सकते हैं। यह सब एफके के साथ कैसे काम करेगा (आखिरकार मैंने एफके का उल्लेख किया है, मुझे इसे नमूने में शामिल करना होगा)। अच्छा, इंतज़ार क्यों?

create table c (i serial, t int references t(i), x text);
--and accordingly a foreign table - the one on newer version...
\c p10
create table c (i serial, t int references t(i), x text);
\c p93
create foreign table f_c(i serial, t int, x text) server p10 options (TABLE_name 'c');
--let’s pretend it had some data before we decided to migrate with triggers to a higher version
insert into c (t,x) values (1,'FK');
--- so now we add triggers to replicate DML:
create trigger tgi before insert on c for each row execute procedure tgf_i();
create trigger tgu before update on c for each row execute procedure tgf_u();
create trigger tgd before delete on c for each row execute procedure tgf_d();

कई तालिकाओं को "ट्रिगर" करने के उद्देश्य से उन तीनों को एक समारोह में लपेटना निश्चित रूप से लायक है। लेकिन मैं नहीं करूंगा। जैसा कि मैं कोई और तालिका नहीं जोड़ने जा रहा हूँ - दो संदर्भित संबंध डेटाबेस पहले से ही इतना गड़बड़ जाल है!

--now, what would happen if we tr inserting referenced FK, that does not exist on remote db?..
insert into c (t,x) values (2,'FK');
/* it fails with:
psql:blog.sql:139: ERROR:  insert or update on table "c" violates foreign key constraint "c_t_fkey"
a new row isn't inserted neither on remote, nor local db, so we have safe data consistencyy, but inserts are blocked?..
Yes untill data that existed untill trigerising gets to remote db - ou cant insert FK with before triggerising keys, yet - a new (both t and c tables) data will be accepted:
*/
insert into t(i) values(4); --I use gap we got by deleting data above, so I dont need to "returning" and know the exact id -less coding in sample script
insert into c(t) values(4);
select * from c;
select * from f_c;

इसमें परिणाम:

psql:blog.sql:109: ERROR:  insert or update on table "c" violates foreign key constraint "c_t_fkey"
DETAIL:  Key (t)=(2) is not present in table "t".
CONTEXT:  Remote SQL command: INSERT INTO public.c(i, t, x) VALUES ($1, $2, $3)
SQL statement "insert into f_c select ($1).*"
PL/pgSQL function tgf_i() line 3 at EXECUTE statement
INSERT 0 1
INSERT 0 1
 i | t | x  
---+---+----
 1 | 1 | FK
 3 | 4 | 
(2 rows)

 i | t | x 
---+---+---
 3 | 4 | 
(1 row)

दोबारा। ऐसा लगता है कि डेटा एकरूपता जगह पर है। आप नई तालिका c के लिए भी डेटा समन्वयित करना प्रारंभ कर सकते हैं…

थक गया? मैं निश्चित रूप से हूं।

निष्कर्ष

अंत में मैं इस दृष्टिकोण को देखते हुए कुछ गलतियों को उजागर करना चाहूंगा। जब मैं अद्यतन विवरण का निर्माण कर रहा था, गतिशील रूप से pg_attribute से सभी स्तंभों को सूचीबद्ध करते हुए, मैंने काफी एक घंटा खो दिया। कल्पना कीजिए कि बाद में मुझे यह जानकर कितना निराशा हुई कि मैं पूरी तरह से UPDATE (सूची) =(सूची) निर्माण के बारे में भूल गया! और फ़ंक्शन बहुत छोटी और अधिक पठनीय स्थिति में आ गया।

तो गलती नंबर एक थी - सब कुछ खुद बनाने की कोशिश करना, सिर्फ इसलिए कि यह इतना पहुंच योग्य लगता है। यह अभी भी है, लेकिन हमेशा की तरह किसी ने शायद इसे पहले से ही बेहतर कर दिया है - यह जांचने के लिए कि क्या वास्तव में ऐसा है, दो मिनट खर्च करने से आप बाद में सोचने के घंटे बचा सकते हैं।

और दूसरी - बात मुझे बहुत आसान लग रही थी जहां वे बहुत गहरे निकले, और मैंने कई मामलों को जटिल बना दिया जो पूरी तरह से पोस्टग्रेएसक्यूएल लेनदेन मॉडल द्वारा आयोजित किए जाते हैं।

इसलिए सैंडबॉक्स बनाने की कोशिश करने के बाद ही मुझे इस दृष्टिकोण के अनुमानों की कुछ हद तक स्पष्ट समझ मिली।

इसलिए योजना बनाने की स्पष्ट रूप से आवश्यकता है, लेकिन जितना आप वास्तव में कर सकते हैं उससे अधिक की योजना न बनाएं।

अनुभव अभ्यास के साथ आता है।

मेरे सैंडबॉक्स ने मुझे एक कंप्यूटर रणनीति की याद दिला दी - आप दोपहर के भोजन के बाद उस पर बैठते हैं और सोचते हैं - "आह, यहाँ मैं पिरामिड बनाता हूँ, वहाँ मुझे तीरंदाजी मिलती है, फिर मैं सन्स ऑफ़ रा में परिवर्तित होता हूँ और 20 लॉन्गबो पुरुषों का निर्माण करता हूँ, और यहाँ मैं दयनीय पर हमला करता हूँ पड़ोसियों। दो घंटे की महिमा। ” और अचानक आप अगली सुबह खुद को काम से दो घंटे पहले पाते हैं "मैं यहां कैसे पहुंचा? मुझे अपने आखिरी लंबे धनुष को बचाने के लिए बिना धोए हुए बर्बर लोगों के साथ इस अपमानजनक गठबंधन पर हस्ताक्षर करने की आवश्यकता क्यों है और क्या मुझे वास्तव में इसके लिए अपने कठोर-निर्मित पिरामिड को बेचने की ज़रूरत है?"

रीडिंग:

  • https://www.PostgreSQL.org/docs/current/static/different-replication-solutions.html
  • https://stackoverflow.com/questions/15343075/update-multiple-columns-in-a-trigger-function-in-plpgsql

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Postgresql में, दो स्तंभों के संयोजन पर अद्वितीय बल दें

  2. कैसे Cosd () PostgreSQL में काम करता है

  3. Psql का उपयोग करके मैं डेटाबेस में स्थापित एक्सटेंशन को कैसे सूचीबद्ध करूं?

  4. SQL, OID को पोस्टग्रेज करता है, वे क्या हैं और वे क्यों उपयोगी हैं?

  5. PostgreSQL में स्थान की गणना और बचत करना