PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Bagaimana saya bisa memastikan bahwa tampilan terwujud selalu up to date?

Saya perlu memanggil REFRESH MATERIALIZED VIEW pada setiap perubahan pada tabel yang terlibat, bukan?

Ya, PostgreSQL dengan sendirinya tidak akan pernah memanggilnya secara otomatis, Anda perlu melakukannya dengan cara tertentu.

Bagaimana saya harus melakukan ini?

Banyak cara untuk mencapai ini. Sebelum memberikan beberapa contoh, perlu diingat bahwa REFRESH MATERIALIZED VIEW perintah tidak memblokir tampilan dalam mode AccessExclusive, jadi saat sedang bekerja, Anda bahkan tidak dapat melakukan SELECT di atas meja.

Meskipun, jika Anda berada di versi 9.4 atau yang lebih baru, Anda dapat memberikannya CONCURRENTLY pilihan:

REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv;

Ini akan memperoleh ExclusiveLock, dan tidak akan memblokir SELECT kueri, tetapi mungkin memiliki overhead yang lebih besar (tergantung pada jumlah data yang diubah, jika beberapa baris telah berubah, maka itu mungkin lebih cepat). Meskipun Anda masih tidak dapat menjalankan dua REFRESH perintah secara bersamaan.

Segarkan secara manual

Ini adalah pilihan untuk dipertimbangkan. Khususnya dalam kasus pemuatan data atau pembaruan batch (misalnya sistem yang hanya memuat banyak informasi/data setelah jangka waktu yang lama) biasanya memiliki operasi di akhir untuk memodifikasi atau memproses data, sehingga Anda dapat dengan mudah menyertakan REFRESH operasi di akhir.

Menjadwalkan operasi REFRESH

Opsi pertama dan banyak digunakan adalah menggunakan beberapa sistem penjadwalan untuk menjalankan penyegaran, misalnya, Anda dapat mengonfigurasi yang serupa dalam tugas cron:

*/30 * * * * psql -d your_database -c "REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv"

Dan kemudian tampilan terwujud Anda akan disegarkan setiap 30 menit.

Pertimbangan

Opsi ini sangat bagus, khususnya dengan CONCURRENTLY pilihan, tetapi hanya jika Anda dapat menerima data yang tidak 100% up to date sepanjang waktu. Perlu diingat, bahwa bahkan dengan atau tanpa CONCURRENTLY , REFRESH perintah memang perlu menjalankan seluruh kueri, jadi Anda harus meluangkan waktu yang diperlukan untuk menjalankan kueri dalam sebelum mempertimbangkan waktu untuk menjadwalkan REFRESH .

Menyegarkan dengan pemicu

Pilihan lainnya adalah memanggil REFRESH MATERIALIZED VIEW dalam fungsi pemicu, seperti ini:

CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
    REFRESH MATERIALIZED VIEW CONCURRENTLY my_mv;
    RETURN NULL;
END;
$$;

Kemudian, di tabel mana pun yang melibatkan perubahan tampilan, Anda melakukan:

CREATE TRIGGER tg_refresh_my_mv AFTER INSERT OR UPDATE OR DELETE
ON table_name
FOR EACH STATEMENT EXECUTE PROCEDURE tg_refresh_my_mv();

Pertimbangan

Ini memiliki beberapa jebakan penting untuk kinerja dan konkurensi:

  1. Setiap operasi INSERT/UPDATE/DELETE harus menjalankan kueri (yang mungkin lambat jika Anda mempertimbangkan MV);
  2. Bahkan dengan CONCURRENTLY , satu REFRESH masih memblokir yang lain, jadi setiap INSERT/UPDATE/DELETE pada tabel yang terlibat akan diserialisasi.

Satu-satunya situasi yang saya pikir sebagai ide bagus adalah jika perubahannya sangat jarang terjadi.

Segarkan menggunakan LISTEN/NOTIFY

Masalah dengan opsi sebelumnya adalah bahwa opsi tersebut sinkron dan membebankan overhead yang besar pada setiap operasi. Untuk memperbaikinya, Anda dapat menggunakan pemicu seperti sebelumnya, tetapi itu hanya memanggil NOTIFY operasi:

CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
    NOTIFY refresh_mv, 'my_mv';
    RETURN NULL;
END;
$$;

Jadi Anda dapat membangun aplikasi yang tetap terhubung dan menggunakan LISTEN operasi untuk mengidentifikasi kebutuhan untuk memanggil REFRESH . Salah satu proyek bagus yang dapat Anda gunakan untuk menguji ini adalah pgsidekick, dengan proyek ini Anda dapat menggunakan skrip shell untuk melakukan LISTEN , sehingga Anda dapat menjadwalkan REFRESH sebagai:

pglisten --listen=refresh_mv --print0 | xargs -0 -n1 -I? psql -d your_database -c "REFRESH MATERIALIZED VIEW CONCURRENTLY ?;"

Atau gunakan pglater (juga di dalam pgsidekick ) untuk memastikan Anda tidak memanggil REFRESH sangat sering. Misalnya, Anda dapat menggunakan pemicu berikut untuk membuatnya REFRESH , tetapi dalam 1 menit (60 detik):

CREATE OR REPLACE FUNCTION tg_refresh_my_mv()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
    NOTIFY refresh_mv, '60 REFRESH MATERIALIZED VIEW CONCURRENLTY my_mv';
    RETURN NULL;
END;
$$;

Jadi itu tidak akan memanggil REFRESH dalam waktu kurang dari 60 detik, dan juga jika Anda NOTIFY berkali-kali dalam waktu kurang dari 60 detik, REFRESH akan dipicu hanya sekali.

Pertimbangan

Sebagai opsi cron, opsi ini juga bagus hanya jika Anda dapat membuka dengan sedikit data basi, tetapi ini memiliki keuntungan bahwa REFRESH dipanggil hanya saat benar-benar dibutuhkan, sehingga Anda memiliki lebih sedikit overhead, dan juga data diperbarui lebih dekat saat dibutuhkan.

OBS:Saya belum benar-benar mencoba kode dan contoh, jadi jika seseorang menemukan kesalahan, salah ketik atau mencobanya dan berhasil (atau tidak), beri tahu saya.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Hibernasi:Buat Indeks

  2. Perbedaan Rails/Postgresql SQL dengan Tanggal

  3. DROP TABLE Postgresql tidak berfungsi

  4. Masalah koneksi dengan SQLAlchemy dan beberapa proses

  5. Cara Mengonversi String ke Nilai Numerik di PostgreSQL