Apa yang terjadi jika dua proses mencoba REFRESH MATERIALIZED VIEW secara bersamaan?

13

Menurut dokumen:

CONCURRENTLY. Refresh tampilan terwujud tanpa mengunci pilihan bersamaan pada tampilan terwujud. (...)

... ISI LAINNYA ...

Bahkan dengan opsi ini hanya satu REFRESH pada satu waktu yang dapat berjalan melawan satu tampilan terwujud .

Saya memiliki fungsi yang memeriksa waktu refresh terakhir untuk tampilan MATERIALISASI dan, jika lebih dari 60 detik telah berlalu, itu akan menyegarkan kembali.

Namun, apa yang akan terjadi jika saya mencoba menyegarkan tampilan terwujud dari dua proses terpisah pada saat yang sama? apakah mereka akan mengantri atau mereka akan membuat kesalahan?

Apakah ada cara untuk mendeteksi ketika PANDANGAN MATERIALISASI sedang disegarkan dan karenanya tidak menyentuhnya?

Saat ini, saya terpaksa mengisi catatan tabel sebelum menyegarkan (mengatur refreshingke true) dan kemudian mengaturnya falseketika proses telah selesai.

EXECUTE 'INSERT INTO refresh_status (last_update, refreshing) 
         VALUES (clock_timestamp(), true) RETURNING id') INTO refresh_id;
EXECUTE 'REFRESH MATERIALIZED VIEW CONCURRENTLY my_mat_view';
EXECUTE 'UPDATE refresh_status SET refreshing=false WHERE id=$1' USING refresh_id;

Kemudian, setiap kali saya memanggil prosedur ini, saya memeriksa yang terbaru last_updatedan refreshingnilainya. Jika refreshingbenar, maka jangan mencoba untuk menyegarkan tampilan terwujud.

EXECUTE 'SELECT 
           extract(epoch FROM now() - (last_update))::integer, 
           refreshing
         FROM refresh_status
         ORDER BY last_update DESC
         LIMIT 1' INTO update_seconds_ago, refreshing;

IF(updated_seconds_ago > 60 AND refreshing = FALSE) THEN
  -- the refresh block above
END IF;

Namun, saya tidak yakin bendera penyegaran diperbarui secara serempak (maksud saya, itu benar-benar menunggu penyegaran untuk benar-benar selesai)

Apakah pendekatan ini rasional atau saya melewatkan sesuatu di sini?

ffflabs
sumber

Jawaban:

13

Seperti disebutkan dalam jawaban ini , " REFRESH MATERIALIZED VIEW CONCURRENTLYmengambil EXCLUSIVEkunci" di atas meja. Mengikuti jejak remah ke dokumentasi, kita dapat membaca bahwa EXCLUSIVEkunci di atas meja "hanya memungkinkan ACCESS SHAREkunci bersamaan , yaitu hanya membaca dari tabel yang dapat dilanjutkan". Dalam paragraf yang sama kita dapat melihat bahwa " EXCLUSIVEkonflik dengan ... EXCLUSIVE", yang berarti bahwa REFRESH MATERIALIZED VIEW CONCURRENTLYpernyataan lain , yang meminta EXCLUSIVEkunci yang sama , harus menunggu sampai EXCLUSIVEkunci sebelumnya dilepaskan.

Jika Anda ingin menghindari menunggu kunci ini untuk periode yang tidak ditentukan, Anda mungkin ingin mengatur variabel sesilock_timeout ke nilai yang masuk akal.

mustaccio
sumber
PS: apakah menurut Anda masuk akal untuk menjaga tabel tambahan ini untuk memberitahu upaya bersamaan (tidak ada permainan kata-kata) bahwa MAT VIEW sedang sibuk dan oleh karena itu harus dibiarkan sendiri walaupun tampaknya perlu menyegarkan?
ffflabs
Ini masalah pendapat; jika Anda pikir itu membantu Anda tentu saja dapat menjaga logika Anda. Perhatikan, bagaimanapun, bahwa fungsi Anda tunduk pada kondisi balapan dan karenanya tidak dapat diandalkan 100%.
mustaccio
Apakah Anda pikir layak untuk memeriksa pg_locks kemudian untuk melihat apakah ada satu referensi tampilan mat?
ffflabs
Sekali lagi, kondisi balapan mungkin: ada kemungkinan bahwa kunci akan ditempatkan di antara Anda memeriksa pg_locksdan mulai menyegarkan Anda. Cara yang tepat untuk mengatasi konflik kunci adalah mengatur batas waktu dan menangani kesalahan.
mustaccio
3

Seperti dicatat oleh mustaccio , pertanyaan ini tumpang tindih secara signifikan dengan Postgres Refresh Materialized View Locks .

Namun, sementara jawaban yang diterima untuk pertanyaan itu memiliki tautan yang menjawab yang ini, jawaban untuk pertanyaan ini tidak secara langsung termasuk di dalamnya.

Jadi, untuk lebih spesifik: Menurut halaman manual PostgreSQL tentang penguncian eksplisit (Tautan ke halaman versi saat ini, untuk PostGres 10), REFRESH MATERIALIZED VIEW CONCURRENTLYmengambil EXCLUSIVEkunci. The EXCLUSIVEkunci muncul untuk memblokir semua kunci lainnya kecuali ACCESS SHARE - yang mencakup lainnya EXCLUSIVEkunci.

Jadi REFRESH MATERIALIZED VIEW CONCURRENTLYpermintaan kedua pada tampilan yang sama akan menunggu kunci yang diperoleh oleh yang pertama dirilis.

RDFozz
sumber
Terima kasih. Saya masih menandai jawaban @ mustaccio yang diterima karena dia mengedit teksnya untuk lebih spesifik pada pertanyaan saya.
ffflabs
0

Berkat jawaban oleh mustaccio dan RDFozz , saya akhirnya mengerti bahwa REFRESH ... CONCURRENTLYmengambil kunci eksklusif adalah alasan yang dikatakan oleh dokumentasi PostgreSQL :

Bahkan dengan opsi ini hanya satu REFRESH pada satu waktu yang dapat berjalan melawan satu tampilan terwujud .

Saya takut bahwa ini berarti segala upaya untuk membuat penyegaran secara simultan akan membuat kesalahan , tetapi berdasarkan jawaban mereka, tidak ada kesalahan khusus yang terlibat. Ini hanya masalah kunci yang akan memungkinkan upaya simultan. Jadi, dokumentasi itu bisa diartikan sebagai:

Kunci yang diperoleh selama operasi ini akan mencegah operasi apa pun selain membaca dari MATERIALIZED VIEW. Upaya lebih lanjut untuk menyegarkan View Terwujud saat REFRESH ... CONCURRENTLY sedang berjalan akan mengantri sampai kunci pertama dilepaskan.

ffflabs
sumber