DBA: نقل قيم SEQUENCE بين قواعد بيانات PostgreSQL

كيف يمكنني نقل إلى آخر قاعدة بيانات PostgreSQL من القيمة المعينة لحقل "زيادة تلقائية" من النوع التسلسلي إذا كان يمكن أن يكون هناك أي عمليات حذف في الجدول ، و "مجرد استبدال max (pk)" لم يعد يعمل؟

قلة من الناس يعرفون أنه على الرغم من أن PG لا توفر ما يصل إلى وظائف الإصدار 10 من أجل معرفة القيمة الأخيرة للتسلسل لمثل هذا الحقل من جلسة أخرى ، إلا أنه لا يزال من الممكن القيام بذلك.



يدعم PostgreSQL حقول " التزايد التلقائي" المعرّفة من قِبل النمط المستعار التسلسلي :
أنواع البيانات smallserial ، التسلسلية و bigserial ليست أنواعًا حقيقية ، ولكنها مجرد أداة مناسبة لإنشاء أعمدة ذات معرّفات فريدة (تشبه خاصية AUTO_INCREMENT في بعض قواعد بيانات إدارة قواعد البيانات).
من الناحية الفنية ، هذا مجرد رابط تلقائي لتعريف DEFAULT للحقل والقيم التي تم إنشاؤها بواسطة كائن SEQUENCE . وأحيانًا أريد أن أنظر إلى هذه القيم - على سبيل المثال ، لنقلها إلى قاعدة بيانات مماثلة في الهيكل .

لكن هذا ليس بالأمر السهل:
currval
إرجاع القيمة التي تم إرجاعها من آخر استدعاء التالي لهذا التسلسل في الجلسة الحالية. (إذا لم يتم استدعاء nextval مطلقًا لتسلسل معين في جلسة معيّنة ، فسيتم إرجاع خطأ.) نظرًا لأن هذه القيمة محدودة بنطاق الجلسة ، فإن هذه الوظيفة تعطي نتيجة يمكن التنبؤ بها ، بصرف النظر عما إذا تم استدعاء nextval لاحقًا في جلسات أخرى أم لا.

عرض النظام Pg_sequences
بدءًا من PostgreSQL 10 ، ظهرت طريقة عرض نظام pg_sequences ، حيث تكون هذه المعلومات مرئية بالفعل دون بذل الكثير من الجهد.

دعنا نحاول سحب هذه المعلومات مع ذلك:

CREATE TABLE tst( id serial --   , val integer ); INSERT INTO tst(val) VALUES(1),(2),(4),(8); 

 TABLE tst; 

 id | val -------- 1 | 1 2 | 2 3 | 4 4 | 8 

هذه هي القيمة id = 4 التي نرغب في الحصول عليها. لكن شخصًا ما حذف جزءًا من السجلات ، وفي الجدول لم يعد:

 DELETE FROM tst WHERE id > 2; 

 id | val -------- 1 | 1 2 | 2 

أولاً ، سنكتشف اسم التسلسل المطابق لحقلنا:

 SELECT pg_get_serial_sequence('tst', 'id'); 

 pg_get_serial_sequence ---------------------- public.tst_id_seq 

الآن استخدم اسم التسلسل الناتج كجدول في الاستعلام:

 SELECT * FROM public.tst_id_seq; 

 last_value | log_cnt | is_called -------------------------------- 4 | 29 | t 

في الواقع ، يقوم حقل last_value أيضًا بتخزين القيمة "الأخيرة" التي تمكن التسلسل من توليدها في وقت الاتصال.

الآن لنقم بإنشاء برنامج نصي بسيط لنقل قيم التسلسل من قاعدة بيانات إلى أخرى باستخدام وحدة dblink :

 --   ,    SELECT ( SELECT nlv FROM dblink( 'host=... port=5432 dbname=... user=... password=...' , $q$ SELECT setval(pg_get_serial_sequence('$q$ || quote_ident(sequence_schema) || $q$.$q$ || quote_ident(sequence_table) || $q$', '$q$ || sequence_column || $q$'), $q$ || lv || $q$) $q$ ) T(nlv bigint) --   ) nlv , * FROM ( SELECT ( SELECT relname FROM pg_class WHERE oid = (dp).refobjid ) sequence_table , ( SELECT attname FROM pg_attribute WHERE (attrelid, attnum) = ((dp).refobjid, (dp).refobjsubid) ) sequence_column , * FROM ( SELECT --    - ( SELECT lv FROM dblink( 'dbname=' || current_database() , $q$ SELECT last_value FROM $q$ || quote_ident(sequence_schema) || $q$.$q$ || quote_ident(sequence_name) || $q$ $q$ ) T(lv bigint) --   ,   ""- ) lv , ( SELECT dp FROM pg_depend dp WHERE (classid, objid, refclassid, deptype) = ('pg_class'::regclass, (quote_ident(sequence_schema) || '.' || quote_ident(sequence_name))::regclass, 'pg_class'::regclass, 'a') LIMIT 1 ) dp --      , * FROM information_schema.sequences WHERE sequence_schema IN ('public') --    ) T ) T WHERE sequence_table !~ '^_'; --      

لكن تذكر أنه إذا كان هناك أي نشاط على قاعدة المصدر ، فستكون النتيجة غير محددة!

Source: https://habr.com/ru/post/ar483424/


All Articles