Mengoptimalkan pembaruan bersamaan di Postgres

9

Saya menjalankan query Postgres bersamaan seperti ini:

UPDATE foo SET bar = bar + 1 WHERE baz = 1234

Setiap kueri memengaruhi jumlah baris K yang tetap, dan saya tidak dapat menemukan cara untuk menegakkan urutan pembaruan baris, saya berakhir dengan deadlock. Saat ini saya memperbaiki masalah dengan menegakkan pesanan dengan tangan, tetapi ini berarti saya harus mengeksekusi lebih banyak permintaan daripada yang biasanya saya lakukan sambil juga meningkatkan kompleksitas pencarian dari O (log N + K) ke O (K log N).

Apakah ada cara untuk meningkatkan kinerja tanpa berakhir rentan terhadap kebuntuan? Saya menduga bahwa mengganti (baz)indeks dengan (baz, id)indeks mungkin berhasil asalkan Postgres memperbarui baris dalam urutan yang sama dengan yang telah memindai mereka, apakah ini pendekatan yang layak untuk dilakukan?

Alexei Averchenko
sumber
Saya sarankan Anda menambahkan CREATE TABLEkode.
ypercubeᵀᴹ

Jawaban:

15

Tidak ada ORDER BYdalam SQL UPDATEperintah. Baris pembaruan Postgres dalam urutan acak:

Untuk menghindari kebuntuan dengan kepastian absolut, Anda bisa menjalankan laporan Anda dalam isolasi transaksi serial . Tapi itu lebih mahal dan Anda perlu bersiap untuk mengulangi perintah pada kegagalan serialisasi.

Tindakan terbaik Anda mungkin adalah untuk mengunci secara eksplisit dengan SELECT ... ORDER BY ... FOR UPDATEdalam subquery atau standalone SELECTdalam transaksi - di tingkat isolasi "baca komitmen" default. Mengutip Tom Lane di pgsql-general :

Seharusnya baik-baik saja --- penguncian FOR UPDATE selalu merupakan langkah terakhir dalam pipa SELECT.

Ini harus melakukan pekerjaan:

BEGIN;

SELECT 1
FROM   foo 
WHERE  baz = 1234
ORDER  BY bar
FOR    UPDATE;

UPDATE foo
SET    bar = bar + 1
WHERE  baz = 1234;

COMMIT;

Indeks multikolom aktif (baz, bar)mungkin sempurna untuk kinerja. Tetapi karena barjelas banyak diperbarui , indeks satu kolom pada (baz)mungkin bahkan lebih baik. Tergantung pada beberapa faktor. Berapa banyak baris per baz? Apakah pembaruan HOT dimungkinkan tanpa indeks multikolom? ...

Jika baz diperbarui secara bersamaan, masih ada kemungkinan kasus sudut untuk konflik (per dokumentasi) :

Dimungkinkan untuk SELECTperintah yang berjalan pada READ COMMITTED tingkat isolasi transaksi dan menggunakan ORDER BYdan klausa penguncian untuk mengembalikan baris yang rusak. ...

Juga, jika Anda harus memiliki kendala unik yang melibatkan bar, pertimbangkan DEFERRABLEkendala untuk menghindari pelanggaran unik dalam perintah yang sama. Jawaban terkait:

Erwin Brandstetter
sumber
1
JIKA saya memesan dengan idatau kolom unik lainnya, bukan bar, seharusnya tidak ada sudut atau hit kinerja, kan?
Alexei Averchenko
@AlexeiAverchenko: Ya, kolom unik yang tidak pernah diperbarui akan sempurna untuk ini - dan indeks multikolom termasuk kolom ini di posisi kedua.
Erwin Brandstetter