SORU
24 HAZİRAN 2013, PAZARTESİ


Nasıl bir UPSERT (BİRLEŞTİR, EKLE ... YİNELENEN UPDATE) PostgreSQL yapabilirim?

Çok sık sorulan bir soruyu burada MySQL INSERT ... ON DUPLICATE UPDATE neden olan bir upsert, nasıl ve standart MERGE operasyonun bir parçası olarak desteklemektedir.

PostgreSQL doğrudan desteklemiyor göz önüne alındığında, bunu nasıl yaparsınız? Aşağıdakileri göz önünde bulundurun:

CREATE TABLE testtable (
    id integer PRIMARY KEY,
    somedata text NOT NULL
);

INSERT INTO testtable (id, somedata) VALUES
(1, 'fred'),
(2, 'bob');

Şimdi "yeni tablo içeriğini olurdu (2, 'Joe'), (3, 'Alan'), dizilerini: . upsert istediğinizi varsayalım

(1, 'fred'),
(2, 'Joe'),    -- Changed value of existing tuple
(3, 'Alan')    -- Added new tuple

Bu insanlar upsert tartışırken bahsediyoruz. Daha da önemlisi, herhangi bir yaklaşım olmalıbirden çok işlem aynı masada çalışan varlığında güvenlisonuç yarış koşullarına karşı açık bir kilitleme ya da aksini savunan kullanarak.

Bu konuda yoğun Insert, on duplicate update in PostgreSQL? ama MySQL sözdizimi alternatifleri hakkında zamanla ilgisiz ayrıntı epey büyümüş de açıklanmıştır. Kesin bir cevap üzerinde çalışıyorum.

(Bu teknikler için de yararlı "Ekle Eğer yoksa, aksi takdirde hiçbir şey yapma", yani "Ekle ... yinelenen anahtarı Yoksay")

CEVAP
24 HAZİRAN 2013, PAZARTESİ


Ve daha yeni 9.5:

PostgreSQL 9.5 ve daha yeni destek INSERT ... ON CONFLICT UPDATE (ON CONFLICT DO NOTHING), yani upsert.

Comparison with ON DUPLICATE KEY UPDATE.

Kullanım the manual - özellikle görmek içinconflict_actionsözdiziminde tümce diyagramı, the explanatory text. (Not: linkler /9.5 yayımlanıncaya kadar/ manuel devel).

Çözüm 9.4 ve eski aksine aşağıda verilmiştir, bu özellik, birden çok çakışan satır ile çalışır ve özel kilitleme ya da yeniden deneme döngüsü gerektirmez.

The commit adding the feature is here the discussion around its development is here.


9.5 konum ve olması gerekmez, geriye dönük olarak uyumlu şimdi okuma durdurmak.


Ve eski 9.4:

PostgreSQL herhangi bir yerleşik UPSERT (MERGE) tesis yok, ve etkin bir şekilde eş zamanlı kullanım karşısında yapmak çok zordur.

This article discusses the problem in useful detail.

Genel olarak iki seçenek arasında seçim yapmak zorunda:

  • Bir deneme döngü içinde tek tek Ekle/güncelleme işlemleri; ya
  • Tablo kilitleme ve toplu iş yaparak birleştirme

Döngü . tek satır yeniden dene

Tek bir satır upserts kullanarak bir deneme döngü birçok bağlantı aynı anda ekler gerçekleştirmeye çalışmak istiyorsanız mantıklı seçenek.

The PostgreSQL documentation contains a useful procedure that'll let you do this in a loop inside the database. En saf çözümlerin aksine kayıp güncelleştirmeleri Ekle ırklara karşı korur,. Sadece READ COMMITTED modunda çalışır ve hareket içinde yaptığın tek şey ise güvenli olduğunu, sadece, ama. Bu işlev, tetikleyici veya ikincil benzersiz anahtarlar benzersiz ihlallerine neden düzgün çalışmaz.

Bu strateji son derece yetersiz. Ne zaman pratik çalışma sırası ve toplu yapmalısın yerine aşağıda açıklandığı gibi upsert.

Bu sorun için pek çok teşebbüs çözümleri al dikkate başarısız, eksik güncelleştirmeleri neden. İki hareket birbiriyle yarış; onları başarıyla INSERTs birini, diğer bir yinelenen anahtar hata alır ve yerine UPDATE yapar. UPDATE blokları geri alma için INSERT beklemekten veya kaydetme. Geri geldiğinde, UPDATE durumu yeniden kontrol sıfır satır maçları UPDATE aslında upsert yapmadı tamamlar olsa seni beklerdi. Sonuç satır sayıları kontrol edin ve yeniden deneyin nerede gerekli.

Bazı aşma çabaları da SEÇME yarışları dikkate başarısız. Eğer açık ve basit: deneyin

-- THIS IS WRONG. DO NOT COPY IT. It's an EXAMPLE.

BEGIN;

UPDATE testtable
SET somedata = 'blah'
WHERE id = 2;

-- Remember, this is WRONG. Do NOT COPY IT.

INSERT INTO testtable (id, somedata)
SELECT 2, 'blah'
WHERE NOT EXISTS (SELECT 1 FROM testtable WHERE testtable.id = 2);

COMMIT;

birkaç hata modu vardır bir kere, daha sonra iki çalıştırmak. Bir güncelleştirme yeniden kontrol ile zaten tartışılan konulardan biridir. Bir de 24 ** aynı anda, sıfır satır eşleşen ve devam ediyor. Sonra ikisi de EXISTS test yapmak olurönceINSERT. Her ikisi de INSERT yani sıfır satır. Bir yinelenen anahtar hata ile başarısız olur.

Bu denememizde bir döngü ihtiyacımız var. Zeki SQL anahtar hataları veya kayıp güncelleştirmeleri önlemek yinelenen düşünebilirsiniz, ama edemezsiniz. Satır sayılarını kontrol etmek veya anahtar hataları işlemek çoğaltmak gerekir (seçilen yaklaşıma bağlı olarak) ve yeniden deneyin.

Lütfen bunun için kendi çözüm rulo yok. Gibi ileti sıralama ile, muhtemelen yanlış.

Kilit ile toplu upsert

Bazen eski varolan bir veri kümesi birleştirmek istediğiniz bir toplu yeni bir veri kümesi olduğu upsert, yapmak istiyorum. Bukesinlikletek bir satır daha verimli upserts ve pratik zaman tercih edilmelidir.

Bu durumda, genellikle aşağıdaki işlemi izleyin:

  • CREATE TEMPORARY tablo

  • COPY veya toplu Ekle temp tabloya yeni veri

  • LOCK hedef tablo IN EXCLUSIVE MODE. Bu SELECT, diğer işlemlere izin verir, ancak tablonun herhangi bir değişiklik yok.

  • Mevcut kayıtları temp tablodaki değerleri kullanarak UPDATE ... FROM;

  • Zaten hedef tabloda bulunmayan satır INSERT;

  • * *36, kilidi serbest.

Örnek soruda verilen örnek için, çok değerli kullanarak 37* *geçici tablo doldurmak için:

BEGIN;

CREATE TEMPORARY TABLE newvals(id integer, somedata text);

INSERT INTO newvals(id, somedata) VALUES (2, 'Joe'), (3, 'Alan');

LOCK TABLE testtable IN EXCLUSIVE MODE;

UPDATE testtable
SET somedata = newvals.somedata
FROM newvals
WHERE newvals.id = testtable.id;

INSERT INTO testtable
SELECT newvals.id, newvals.somedata
FROM newvals
LEFT OUTER JOIN testtable ON (testtable.id = newvals.id)
WHERE testtable.id IS NULL;

COMMIT;

Okuma ile ilgili

Ne MERGE hakkında?

SQL-standart MERGE aslında kötü eşzamanlılık semantik tanımladı ve ilk bir tablo kilitleme olmadan upserting için uygun değildir.

Veri birleştirme için gerçekten yararlı OLAP bir ifade, ama aslında eşzamanlılık-güvenli upsert için yararlı bir çözüm değil. İnsanlar diğer DBMSes upserts MERGE kullanmak için bir sürü tavsiye var, ama aslında yanlış.

Diğer DBs:

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Bart Baker

    Bart Baker

    1 Aralık 2006
  • Garrett Müller

    Garrett Mül

    26 HAZİRAN 2009
  • MndsgnVEVO

    MndsgnVEVO

    26 Kasım 2013