2011-06-13 20 views
7

Postgresql'deki hemen hemen aynı tabloların arasındaki farkı almaya çalışıyorum. Ben koşuyorum geçerli sorgu geçerli:Postgresql UNION, tek tek sorguları çalıştırdığı sürece 10 kez uzun sürüyor

SELECT * FROM tableA EXCEPT SELECT * FROM tableB; 

ve

SELECT * FROM tableB EXCEPT SELECT * FROM tableA; 

yukarıdaki sorguları Her çalıştırmak için yaklaşık 2 dakika sürer (Onun büyük tablo)

Ben iki birleştirmek istedim zaman kazanmak için umuyor, bu yüzden denedim:

SELECT * FROM tableA EXCEPT SELECT * FROM tableB 
UNION 
SELECT * FROM tableB EXCEPT SELECT * FROM tableA; 

Ve çalışırken, 20 dakika sürer! Her sorguyu tek tek çalıştırmak için en fazla 4 dakika süreceğini tahmin ediyorum.

UNION bunu yapmak için çok uzun süren bir iş var mı? Ya da bunu hızlandırabileceğim herhangi bir yol var mı (UNION ile olsun ya da olmasın)?

GÜNCELLEŞTIRME: Sorguyu UNION ALL ile birlikte yürütmek, her birinin kendi başına çalıştığı sürenin neredeyse 4 katı olmak üzere 15 dakika sürer. UNION (tümü) nin bunu hızlandırmayacağını söyleyerek düzeliyorum mu?

+0

Sadece tabloA' veya 'tableB' içinde yinelenmeleri gerekecek olan çiftler var mı? Aksi takdirde 'UNION ALL' ı deneyin. –

+0

@ScrumMeister: Bunu daha önce hiç düşünmemiştim. Birleşim, tek bir tablodaki yinelemeleri kaldırır. Sadece iki sendikalı tablo arasında kopyalar çıkardığını düşündüm. Bunu araştırmam gerekebilir. – RThomas

+0

"EXPLAIN ANALYZE" çıktısını yayınlayabilir misiniz? –

cevap

11

"Ek iş" sorununuzla ilgili olarak. Evet. Birlik sadece iki soruyu birleştirmekle kalmaz, aynı zamanda kopyaları giderir ve çoğaltır. Farklı bir deyim kullanmakla aynı şey. Bu nedenle, özellikle "sendikaların hepsi" ifadelerinizle birleştirildiğinde, muhtemelen daha hızlı olacaktır.

Devamı burada: birinci ve ikinci sorgunun sonuçlarını birleştirerek ek olarak http://www.postgresql.org/files/documentation/books/aw_pgsql/node80.html

+0

Az önce "SELECT * FROM tableA EXCEPT SELECT * FROM tableB UNION TÜM SEÇİMİ * FROM tableB'DEN SEÇMEK İSTEDİĞİNİZ * tablodan"; 15 dakika sürdü, bu yüzden iki sorguyu ayrı ayrı yürütmek kadar hızlı yok. – lanrat

+0

Bunu doğru cevap olarak seçiyorum, ancak yine de sorguları çalıştırmanın hızlandırdığı görülüyor. – lanrat

+0

@RThomas, "tümünü birleştir" ifadesini ekleyerek gereksiz değerleri de eklerse ne olur? – Lokesh

3

, varsayılan olarak UNION da yinelenen kayıtları kaldırır. (bakınız http://www.postgresql.org/docs/8.1/static/sql-select.html). İki sorgu arasındaki yinelenen kayıtların kontrol edilmesinde yer alan ekstra çalışma, muhtemelen ekstra süreden sorumludur. Bu durumda, herhangi bir çift kayıt olmamalıdır, bu nedenle çoğaltmalar arayan ekstra çalışma UNION ALL belirtilerek önlenebilir.

SELECT * FROM tableA EXCEPT SELECT * FROM tableB 
UNION ALL 
SELECT * FROM tableB EXCEPT SELECT * FROM tableA; 
+0

Cevabımı yazarken biraz yavaşlamış gibi görünüyor. LazyDBA – dave

-2

Sen TABLEA TAM DIŞ sadece 1 masa tarama ile size (bir propre ile birleşim koşulu) istediğini verecekti TABLEB, JOIN kullanabilirsiniz muhtemelen yukarıda 2 sorgular daha hızlı olacaktır.

Daha fazla bilgi gönderin.

2

Kodunuzun, sonuç istediğiniz sonucu döndürdüğünü sanmıyorum. Bunu yapmak istediğinizi düşünürüm:

SELECT * 
    FROM (
     SELECT * FROM tableA 
     EXCEPT 
     SELECT * FROM tableB 
     ) AS T1 
UNION 
SELECT * 
    FROM (
     SELECT * FROM tableB 
     EXCEPT 
     SELECT * FROM tableA 
     ) AS T2; 

Başka bir deyişle, birbirini dışlayan münferit üyelerin olmasını istersiniz.Eğer öyleyse, SQL ilişkisel operatör önceliği kadar okumak gerekir;) Ve olduğu zaman, yukarıda rasyonalize edilebilir fark edilebilir: alt sorgular kullanarak,

SELECT * FROM tableA 
UNION 
SELECT * FROM tableB 
EXCEPT 
SELECT * FROM tableA 
INTERSECT 
SELECT * FROM tableB; 

FWIW (türetilmiş tablolar T1 ve T2) açıkça ilişkisel operatör önceliği, orijinal sorgu şudur (aksi örtük ne olurdu) göstermek için:

:

SELECT * 
    FROM (
     SELECT * 
      FROM (
       SELECT * 
        FROM tableA 
       EXCEPT 
       SELECT * 
        FROM tableB 
       ) AS T2 
     UNION 
     SELECT * 
      FROM tableB 
     ) AS T1 
EXCEPT 
SELECT * 
    FROM tableA; 

yukarıda relationalised edilebilir

SELECT * 
    FROM tableB 
EXCEPT 
SELECT * 
    FROM tableA; 

... ve bence amaçlanan bir şey değil.

+0

için Kudos Açıklama için teşekkürler! Sağladığınız ilk sorguyu çalıştırdım, ancak yine de iki ayrı sorgunun çalıştırılmasından çok daha uzun sürüyor. Çalıştığım iki sorgu tam olarak istediğim şey; Sadece daha hızlı istiyorum :). Sağladığınız ikinci sorgu> 1 saat sürdü, bu yüzden durdum (tüm diğerlerinin nerede 10 dakikadan az olduğu) – lanrat

İlgili konular