PostgreSQL'de tablo verilerini atomik olarak değiştirme


14

SELECTİşlem sırasında gelen ifadeleri etkilemeden bir tablonun tüm içeriğini değiştirmek istiyorum .

Kullanım durumu, düzenli olarak ayıklanan ve bir PostgreSQL tablosunda saklanması gereken posta kutusu bilgilerini depolayan bir tabloya sahip olmaktır. Sürekli aynı tabloyu sorgulayan bir uygulama kullanan birçok istemci var.

Normalde, (sözde kod gelen) gibi bir şey yapardım ...

BEGIN TRANSACTION
TRUNCATE TABLE
INSERT INTO
COMMIT

Ancak maalesef bu işlem sırasında tablo okunamıyor; INSERT INTOtamamlanması gereken zamandan dolayı . Masa kilitli.

RENAME TABLEMySQL'de bu sorunları önlemek için atomik komutlarını kullanırdım ...

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;

PostgreSQL'de bunu nasıl başarabilirim?

Bu sorunun amaçları için yabancı anahtar kullanmadığımı varsayabilirsiniz.


Neden tabloya satır eklerken tablonun okunamayacağını düşünüyorsunuz? Kesme tablosunun tüm oturumlarda hemen etkisi olacaktır; ancak ekler (sahte kodunuzun da belirttiği gibi hepsini saran bir işlemin içinde yapılırsa) siz taahhüt edene kadar diğer oturumlar tarafından görülemez. Diğer oturumlar tablodan seçim yapabilir ve siz tamamlayana kadar boş bir tablo görür.
zgguy

2
@zgguy TRUNCATEkomut, tabloda bir AccessExclusive kilidi alır, böylece bu işlem gerçekleşene veya geri alınana kadar başka kimse tablodan okuyamaz.
Josh Kupershmidt

2
deleteBunun yerine kullanırsanız truncate, okuyucuları engellemeden daha yavaş olacaktır. Kaç satırı silmeniz gerekiyor?
a_horse_with_no_name

@a_horse_with_no_name Genellikle birçok varchar sütunu olan 200-300k satır arasında. Bekleme süresi DELETEve INSERTçok uzun olurdu.
Clarkey

Yanıtlar:


21

Doğru, gerçekleştirdiğiniz TRUNCATE TABLE komut "... üzerinde çalıştığı her bir tablo için bir ACCESS EXCLUSIVE kilidi alır ", bu nedenle gönderdiğiniz ilk SQL bloğunda, bu süreden sonra tabloya erişmeye çalışan diğer istemciler INSERTtamamlanana kadar engellenir ve sen COMMIT.

MySQL'e özel kodunuzdakiyle aynı geçici çözümü kullanabilirsiniz; Postgres kabaca aynı sözdizimini destekler ve benzer kilitleme davranışına sahip olacaktır. Zekâ için:

BEGIN;
-- You probably want to make sure that no one else is
-- INSERT / UPDATE / DELETE'ing from the original table, otherwise
-- those changes may be lost during this switchover process. One way
-- to do that would be via:
-- LOCK TABLE "table" IN SHARE ROW EXCLUSIVE mode;
CREATE TABLE "table_new" (LIKE "table");
INSERT INTO "table_new" ...;

-- The ALTER TABLE ... RENAME TO command takes an Access Exclusive lock on "table",
-- but these final few statements should be fast.
ALTER TABLE "table" RENAME TO "table_old";
ALTER TABLE "table_new" RENAME TO "table";
DROP TABLE "table_old";

COMMIT;

Ekstra bonus: Postgres aslında MySQL'den farklı olarak işlemsel DDL'yi destekler, bu nedenle yukarıdaki işlemi GERİ BİLDİRmeniz gerekiyorsa, güvenle yapabilirsiniz.


Bu konuda biraz test yapacağım, cevabınız için teşekkürler. Ben kullandıysanız LOCK TABLE, önerilen bu yöntemi, daha önce yine kilidini gerekir COMMIT, yoksa kendisi kilidini olacak?
Clarkey

1
EDIT: Bu belgede aşağıdaki ifadeyi bulundu : "UNLOCK TABLE komutu yok; kilitler her zaman işlem sonunda serbest bırakılır."
Clarkey

2
Burada eksik olan bir şey, hala ait olan tüm kısıtlamalar_old
Intellix

@Intellix bu konuyu biraz açıklayabilir misiniz? Kısıtlamaların sadece eski tabloya göre adlandırıldığı veya sadece eski tabloyla ilgili olduğu anlamına mı geliyor (yani, kısıtlamaların etkili bir şekilde düştüğü anlamına mı geliyor)?
maerics

Tablo oluşturma ( -- LOCK TABLE "table" IN ROW EXCLUSIVE mode;) 'dan önceki yorum, spesifikasyonlara göre kaynak tabloya bir güncelleme / ekleme işleminden korumak için yetersiz görünüyor. ROW EXCLUSIVEHerhangi bir çakışma olmadan iki kilit elde edilebilir ( postgresql.org/docs/10/explicit-locking.html#LOCKING-TABLES içindeki Tablo 13.2'ye bakın ). Veri güncellemelerini önlemek için en az bir SHAREkilide ihtiyacınız vardır .
Pilou
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.