Postgresql'de milyonlarca satırı bir tablodan diğerine nasıl verimli bir şekilde kopyalayabilirim?


36

İki tane veritabanı tablom var. Birinde yüz milyonlarca kayıt var. Hadi bunu söyleyelim history. Diğeri günlük olarak hesaplanır ve tüm kayıtlarını historybirine kopyalamak istiyorum .

Yaptığım şey kaçmaktı:

INSERT INTO history SELECT * FROM daily

Bir süre hile yaptı, ancak kayıt sayısı artmaya devam ettikçe yavaşlamaya başladı. Şimdi kopyalanmış gereken yaklaşık 2 milyon kayıtları dailyiçin historytek bir işlemle ve eksiksiz için çok uzun sürer.

Verileri bir tablodan diğerine kopyalamanın başka, daha etkili bir yolu var mı?

Yanıtlar:


10

Geçmişi uzun süre (aylarca) saklamayı planlıyorsanız, bölümleme seçeneklerine bir göz atmanızı öneririm - her gün veya hafta vb. İçin bir bölüm olabilir. Ayrıca, tarihçe tablonuzdaki erişim kalıplarına da bağlıdır (tarihler arasında verilere erişen sorgular çalıştırıyor musunuz? Çok fazla toplama yapıyor musunuz?). Toplamları / özetleri saklamak için somutlaştırılmış görünümlere bir göz atın. http://www.postgresql.org/docs/9.3/static/ddl-partitioning.html http://www.postgresql.org/docs/9.3/static/sql-creatematerializedview.html


Cevap için teşekkürler. Gidecek tek yol gibi görünüyor. Verileri aylara göre bölümlere ayırmam ve böylece yeniden indeksleme yapmam gerekiyordu (çünkü indeks rejenerasyonu burada bir problemdi).
Milovan Zogovic

16

Masayı csv biçiminde boşalt

COPY table TO '/tmp/table.csv' DELIMITER ',';

Büyük miktarda veri için çok daha verimli olan COPY komutunu kullanın.

COPY table FROM '/tmp/table.csv' DELIMITER ',';

Daha fazla bilgi için postgres belgelerini http://www.postgresql.org/docs/current/static/sql-copy.html adresinden kontrol edin .


1
Hala çok, çok yavaş çalışıyor ... Belki de böyle büyük bir endeksi yeniden oluşturmak zorunda kalmadan bir şeyler yapmalı. historyTabloda 160 milyon satır var ve 3 milyon daha ekledik.
Milovan Zogovic

2
Boş bir tabloyu dolduruyorsunuz veya zaten mevcut olandan daha fazla satır ekliyorsanız, genellikle kümelenmemiş dizinleri bırakmak ve aktarım tamamlandığında bunları yeniden oluşturmak daha verimlidir (o sırada tablonun / masaların aktif kullanımı olmadığı sürece). )
David Spillett

BTW, bu tek seferlik bir işlem mi, yoksa düzenli olarak yapmanız gereken bir şey mi? Düzenli olarak ise, bir tetikleyici yaratmanızı öneriyorum, böylece her zaman bu sıkıntıdan geçmek zorunda kalmazsınız.
Fabrizio Mazzoni

@FabrizioMazzoni - Belirli bir zamanda günlük olarak gerçekleştirilmelidir (zaman içinde anlık görüntüler alarak).
Milovan Zogovic

@DavidSpillett - gerçekten! Düşürme endeksleri ithalatı çok hızlı hale getiriyor (yukarıdaki cevabımı görün), ancak, yeniden oluşturma endeksleri saatler alır (veritabanında 160M satırım olduğundan) ..
Milovan Zogovic

13

Sorun endekslerle oldu. historyTablo 160M endeksli satırları vardı. Ya çalıştırarak ya COPY FROMda INSERT INTO .. SELECTsatır eklemek için değil, dizinleri güncellemek çok zaman alıyordu. Dizinleri devre dışı bıraktığımda, 10M'de 3M satırları içeri aktardı. Şimdi büyük masayı yeniden düzenlemek için daha hızlı bir yol bulmalıyım.


3
Bir tarih tablosunda indekslere ihtiyacınız var mı?
Sherlock

2
CONCURRENTLY anahtar sözcüğünü kullanarak dizini ekleyin
Akvel

10

Psql aracını kullanabilirsiniz , aşağıdaki gibi verimli olabilirim,

psql -h ${DAILY_HOST_IP} -p ${PG_PORT} ${DB_NAME} ${USER_NAME} -c "copy daily to stdout " | psql -h ${HISTORY_HOST_IP} -p ${PG_PORT} ${DB_NAME} ${USER_NAME}  -c "copy history from stdin"

Ayrıca bir kabuk betiği yazabilirsiniz.


Ara dosya olmadan harika bir çözüm. Çok hızlı, ben normal disk ve ağ dosya sistemi arasında 1h20 (indeksler olmadan) 950 milyon satırlık tabloyu kopyaladım.
Le Droid

3

Elbette bu sorunuza kesin bir cevap değildir, ancak historytabloya erişmeniz gerekmiyorsa , bir SQL dökümü de oluşturabilirsiniz:

pg_dump -h host -p port -w -U user db > dump.sql

Daha sonra gitfarkı hesaplamak ve bunu verimli bir şekilde saklamak gibi bir araç kullanılabilir .

git add dump.sql
git commit -m "temp dump"
git gc --aggressive

Bu yararlıdır, çünkü veritabanındaki çoğu bölüm her gün değişmez. Her gün için tam bir kopya saklamak yerine, iki gün arasındaki farkı saklayabilirsiniz.

crontabHer gün çöplük işlenecek bir iş kullanabilirsiniz .

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.