Saya ingin mengganti seluruh isi tabel, tanpa memengaruhi SELECT
pernyataan yang masuk selama proses.
Kasus penggunaan adalah memiliki tabel yang menyimpan informasi kotak surat yang diekstraksi secara teratur, dan perlu disimpan dalam tabel PostgreSQL. Ada banyak klien yang menggunakan aplikasi yang terus-menerus menanyakan tabel yang sama.
Biasanya, saya akan melakukan sesuatu seperti (pseudocode incoming) ...
BEGIN TRANSACTION
TRUNCATE TABLE
INSERT INTO
COMMIT
Namun sayangnya tabel tidak dapat dibaca selama proses ini; karena waktu yang dibutuhkan INSERT INTO
untuk menyelesaikan. Meja dikunci.
Di MySQL, saya akan menggunakan RENAME TABLE
perintah atom mereka untuk menghindari masalah ini ...
CREATE TABLE table_new LIKE table;
INSERT INTO table_new;
RENAME TABLE table TO table_old, table_new TO table; *atomic operation*
DROP TABLE table_old;
Bagaimana saya bisa mencapai ini di PostgreSQL?
Untuk keperluan pertanyaan ini, Anda dapat menganggap saya tidak menggunakan kunci asing.
sumber
TRUNCATE
perintah akan mendapatkan kunci AccessExclusive di atas meja, jadi tidak ada orang lain yang bisa membaca dari tabel sampai transaksi itu dilakukan atau dibatalkan.delete
bukannyatruncate
itu akan lebih lambat, tapi tanpa pembaca menghalangi. Berapa banyak baris yang perlu Anda hapus?DELETE
danINSERT
akan terlalu lama.Jawaban:
Benar,
TRUNCATE TABLE
perintah yang Anda jalankan "... memperoleh kunci AKSES EKSKLUSIF pada setiap tabel tempat operasinya ", jadi pada blok SQL pertama yang Anda pasang, setiap klien lain yang mencoba mengakses tabel setelah waktu tersebut akan diblokir hingga AndaINSERT
selesai dan AndaCOMMIT
.Anda dapat menggunakan solusi yang sama seperti pada kode khusus MySQL Anda; Postgres mendukung kira-kira sintaks yang sama dan akan memiliki perilaku penguncian yang serupa. Yakni:
Bonus tambahan: Postgres sebenarnya mendukung DDL transaksional, tidak seperti MySQL, jadi jika Anda perlu ROLLBACK transaksi di atas, Anda dapat melakukannya dengan aman.
sumber
LOCK TABLE
metode yang Anda sarankan, apakah saya perlu membuka kunci lagi sebelumCOMMIT
, atau akankah itu membuka kunci sendiri?_old
-- LOCK TABLE "table" IN ROW EXCLUSIVE mode;
) tampaknya tidak memadai untuk melindungi dari pembaruan / masukkan ke tabel sumber sesuai dengan spesifikasi. DuaROW EXCLUSIVE
kunci dapat diperoleh tanpa konflik apa pun (lihat Tabel 13.2 di postgresql.org/docs/10/explicit-locking.html#LOCKING-TABLES ). Untuk mencegah pembaruan data, Anda memerlukan setidaknyaSHARE
kunci.