Postgres, MVCC, dan Mengunci

8

Saya memiliki serangkaian pernyataan SQL yang terlihat seperti berikut:

BEGIN;
SELECT counter FROM table WHERE id=X FOR UPDATE;
REALLY COMPLEX QUERY;
UPDATE table SET counter=Y WHERE id=X;
END;

Saya ingin mencegah penghitung agar tidak dibaca saat saya menghitung ulang nilainya, tetapi menurut dokumen Postgres "Kunci tingkat-baris tidak memengaruhi kueri data; mereka hanya memblokir penulis pada baris yang sama."

Pertanyaan:

  1. Apa gunanya kunci baris "eksklusif" jika tidak mencegah pembacaan? Apakah hanya untuk mencegah transaksi lain dari mengambil kunci saham?
  2. Jika saya membaca baris dengan SELECT ... FOR SHARE, apakah itu menghasilkan pengaruh yang sama dengan kunci "eksklusif"?
  3. Apakah mungkin untuk mematikan MVCC untuk tabel / skema / database dan mengizinkan penulisan di tempat?
Kevin
sumber

Jawaban:

5

ke 1) Setiap sesi lain akan membaca data yang dimodifikasi oleh transaksi Anda seperti sebelum pernyataan "MULAI" Anda selama transaksi Anda tidak dilakukan. Segera setelah transaksi Anda dilakukan, itu akan membaca nilai baru dari penghitung. Intinya adalah bahwa orang lain tidak harus menunggu dan akan selalu melihat basis data yang konsisten.

ke 2), 3) Mengapa Anda tidak mencobanya dengan "ACCESS EXCLUSIVE"? (lihat http://www.postgresql.org/docs/current/static/explicit-locking.html )

Suntingan: Jika Anda tidak suka mengunci seluruh tabel dengan kunci "AKSES EKSKLUSIF", Anda juga bisa menggunakan "Kunci Penasihat" (lihat bagian 13.3.4 dalam tautan di atas).

jp
sumber
1

Jika bacaan yang ingin Anda blokir adalah eksekusi simultan dari transaksi yang sama hanya dengan data yang berbeda, gunakan pernyataan UPDATE dengan klausa pengembalian.

Lihat dokumen pada pernyataan UPDATE. Untuk menjawab pertanyaan Anda tentang titik kunci baris eksklusif, itu untuk mencegah inkonsistensi data dari pembaruan simultan. Pembaca mendapatkan tampilan yang konsisten dari basis data setiap saat.

Ketema
sumber
1

Dalam contoh kode yang Anda berikan, semua pembacaan baris itu akan melihat nilai lama hingga transaksi tersebut dilakukan.

1) Pertimbangkan contoh kode yang dijalankan dua kali secara bersamaan, dengan nilai yang sama X. Jika instance A telah berjalan select ... for updatemaka ia telah mengunci baris itu sampai komit. Mesin virtual B, melakukan hal yang sama, akan memblokir mencoba mengambil kunci dengan cara yang sama. Hanya ketika A melakukan, B dapat melanjutkan. B kemudian akan mendapatkan nilai A yang tertinggal dalam pembaruan terakhirnya.

Jika Ytergantung pada nilai apa yang select ... for updatedibaca kueri, atau bacaan lain di bagian 'kompleks', maka ini akan memiliki efek yang sama seperti jika dijalankan secara seri - Anda tidak mendapatkan kondisi balapan di mana salah satu hasilnya akan dibuang.

Jika Ymurni hasil dari query kompleks di tengah, kemudian jalankan secara paralel tanpa select ... for updatekeduanya akan melakukan pembaruan yang sama.

2) for shareakan memungkinkan pilihan lain pada baris itu untuk melanjutkan, tetapi akan menyebabkan hal lain mencoba select ... for updateatau update ...memblokir sampai selesai. Jika kode sampel dijalankan dua kali, secara bersamaan, mereka akan menemui jalan buntu saat mencapai updatepernyataan, menyebabkan salah satu dari mereka dibatalkan.

3) Tidak. Melakukan ini berbahaya, karena pembaca dapat membaca bidang yang setengah diperbarui. (Atau baca sisa bidang yang diperbarui setelah awal membaca.) Itu juga dapat merusak konsistensi, menunjukkan kepada pembaca nilai yang diperbarui setelah dimulainya transaksi.

MaHuJa
sumber