Cepat atau lambat, banyak yang dihadapkan dengan kebutuhan untuk secara besar-besaran memperbaiki sesuatu dalam entri tabel. Saya sudah mengatakan bagaimana melakukannya dengan lebih baik , dan bagaimana - lebih baik tidak melakukannya. Hari ini saya akan berbicara tentang aspek kedua dari pembaruan massal - pemicu pemicu .Misalnya, pada tabel di mana Anda perlu memperbaiki sesuatu, pemicu jahat hang ON UPDATE
, mentransfer semua perubahan ke beberapa agregat. Dan Anda perlu memperbarui semuanya (menginisialisasi bidang baru, misalnya) dengan sangat hati-hati sehingga unit-unit ini tidak terpengaruh.Mari matikan saja pemicunya!
BEGIN;
ALTER TABLE ... DISABLE TRIGGER ...;
UPDATE ...;
ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;
Sebenarnya, itu saja - semuanya sudah menggantung .Karena itu ALTER TABLE
memaksakan kunci AccessExclusive , di mana tidak ada yang berjalan secara paralel, bahkan yang sederhana SELECT
, dapat membaca apa pun dari tabel. Artinya, sampai transaksi ini selesai, semua orang yang ingin "membaca" akan menunggu. Dan kita ingat bahwa UPDATE
kita melakukan-o-olgi ...Ayo cepat matikan, lalu nyalakan dengan cepat!
BEGIN;
ALTER TABLE ... DISABLE TRIGGER ...;
COMMIT;
UPDATE ...;
BEGIN;
ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;
Di sini situasinya lebih baik, waktu tunggu jauh lebih singkat. Tetapi hanya dua masalah yang merusak semua keindahan:ALTER TABLE
dia menunggu semua operasi lain di atas meja, termasuk lama SELECT
- Sementara pemicu dimatikan, setiap perubahan dalam tabel akan terbang , bahkan bukan kita. Dan yah, itu tidak akan masuk ke unit, meskipun harus. Masalah!
Manajemen Variabel Sesi
Jadi, dalam versi sebelumnya, kita menemukan titik penting - kita perlu mengajarkan pemicunya untuk membedakan perubahan โkitaโ di tabel dari โbukan milik kitaโ. Lewati "milik kita" sebagaimana adanya, tetapi "bukan milik kita" - pemicu. Anda dapat menggunakan variabel sesi untuk ini .session_replication_role
Baca manual :Variabel pemicu juga dipengaruhi oleh variabel konfigurasi session_replication_role . Pemicu yang diaktifkan tanpa instruksi tambahan (default) akan menyala ketika peran replikasi adalah "asal" (default) atau "lokal". Pemicu yang diaktifkan oleh indikasi ENABLE REPLICA
akan aktif hanya jika mode sesi saat ini adalah "replika", dan pemicu yang diaktifkan oleh indikasi ENABLE ALWAYS
akan menyala terlepas dari mode replikasi saat ini.
Saya menekankan bahwa konfigurasi tidak berlaku untuk semua sekaligus, seperti ALTER TABLE
, tetapi hanya untuk koneksi khusus kami yang terpisah. Total sehingga tidak ada aplikasi yang memicu kebakaran:SET session_replication_role = replica;
UPDATE ...;
SET session_replication_role = DEFAULT;
Kondisi di dalam pemicu
Tetapi opsi di atas berfungsi untuk semua pemicu sekaligus (atau Anda harus "memicu" pemicu sebelumnya yang tidak ingin Anda nonaktifkan). Dan jika kita perlu "mematikan" satu pemicu spesifik ? Variabel sesi "pengguna"akan membantu kami dalam hal ini :Nama parameter ekstensi ditulis sebagai berikut: nama ekstensi, titik, dan kemudian nama parameter itu sendiri, seperti nama lengkap objek dalam SQL. Sebagai contoh: plpgsql.variable_conflict.
Karena parameter non-sistem dapat diatur dalam proses yang tidak memuat modul ekstensi yang sesuai, PostgreSQL menerima nilai untuk nama apa pun dengan dua komponen .
Pertama, ubah pemicunya, kira-kira seperti ini: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;
...
By the way, ini bisa dilakukan "menguntungkan", tanpa kunci, melalui CREATE OR REPLACE
fungsi pemicu. Dan kemudian dalam koneksi khusus kita memadukan variabel "kita":
SET mycfg.my_table_convert_process = 'TRUE';
UPDATE ...;
SET mycfg.my_table_convert_process = '';
Apakah Anda tahu cara lain? Bagikan komentar Anda.