Postgreslerden satırları toplu olarak almanın en etkili yolu


23

PostgreSQL'den çok sayıda satırı silmek için en etkili yolun ne olacağını merak ediyorum, bu işlem her gün tekrarlanan bir görevin bir parçası olacaktı; Silinecek binlerce, potansiyel olarak milyonlarca satır olabilir.

Her satırda bir tane birincil anahtar dosyası var. Düşündüğüm iki seçenek aşağıdaki satırlar üzerindeydi, ancak PostgreSQL'in içindekileri yeterince iyi bir karar verebilecek kadar iyi bilmiyorum / anlayamıyorum.

  • DELETEDosyadaki her satır için bir sorgu yürütün , basit bir WHEREbirincil anahtarla (veya nbir IN()cümle kullanarak gruplar halinde silmeleri gruplandırın )
  • Birincil tuşları COPYkomutu kullanarak geçici bir tabloya alın ve ardından bir birleştirme kullanarak ana tablodan silmek

Herhangi bir öneri çok takdir edilecektir!


1
Aynı soru burada daha ayrıntılı olarak cevaplandı: stackoverflow.com/a/8290958
Simon

Yanıtlar:


25

İkinci seçeneğiniz çok daha temiz ve buna değecek kadar iyi performans gösterecek. Alternatifiniz, planlamak ve yürütmek için oldukça acı verici olan devasa sorgular oluşturmaktır. Genel olarak PostgreSQL'in buradaki işi yapmasına izin vererek daha iyi olacaksınız. Genel olarak, onbinlerce satır üzerinde, yeterince performans gösterdiğiniz şekilde güncellemeler buldum, ancak yapmaktan kaçınmak için önemli bir şey var.

Bunu yapmanın yolu, silme işleminde bir seçim ve bir birleşim kullanmaktır.

DELETE FROM foo WHERE id IN (select id from rows_to_delete);

Hiçbir koşul altında geniş bir tabloyla aşağıdakileri yapmamalısınız:

DELETE FROM foo WHERE id NOT IN (select id from rows_to_keep);

Bu genellikle, performansı oldukça problemli kılacak şekilde iç içe geçmiş bir döngü birleşmesine neden olacaktır. Bu rotaya gitmek zorunda kalırsanız, bunun yerine şunu yapın:

DELETE FROM foo 
WHERE id IN (select id from foo f 
          LEFT JOIN rows_to_keep d on f.id = d.id
              WHERE d.id IS NULL);

PostgreSQL genellikle kötü planlardan kaçınmakta oldukça iyidir ancak yine de iyi ve kötü planlar arasında büyük fark yaratabilecek dış birleşmeleri içeren durumlar vardır.

Bu biraz daha uzaklarda dolaşıyor, ancak IN'den NOT IN'e gidip sorgu performans tankını izlemenin kolay olmasından dolayı bahsetmeye değer olduğunu düşünüyorum.


Bu çok yardımcı oldu, teşekkürler! Ancak, "birleştirme sorguları" kullanmanın bu özel durumda daha verimli olduğunu buldum. Örneğin, IN ( select id from foo except select id from rows_to_keep ) bkz. Postgresql.org/docs/9.4/static/queries-union.html
Ufos

1

Bu soruyla karşılaştım çünkü benzer bir sorunum vardı. 300M + satırı olan bir veritabanını temizliyorum, son veritabanı ise orijinal verilerin yalnızca% 30'una sahip olacak. Benzer bir senaryo ile karşı karşıyaysanız, yeni bir tabloya eklemek ve silmek yerine yeniden indekslemek daha kolaydır.

Gibi bir şey yap

CREATE temp_foo as SELECT * FROM foo WHERE 1=2;
INSERT INTO temp_foo (SELECT * FROM foo where foo.id IN (SELECT bar.id FROM BAR);

Foo ve çubukta düzgün indeksleme sayesinde, Seq taramalarını önleyebilirsiniz.

Sonra tabloyu yeniden indekslemeniz ve yeniden adlandırmanız gerekir.

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.