PostgreSQL Antipatterns: mengubah data melewati pemicu

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 TABLEmemaksakan 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 UPDATEkita 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 REPLICAakan aktif hanya jika mode sesi saat ini adalah "replika", dan pemicu yang diaktifkan oleh indikasi ENABLE ALWAYSakan 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 REPLACEfungsi 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.

All Articles