2013-06-14 40 views
17

'dan önemli ölçüde daha hızlı Bir tablo var (MainTable) biraz üzerinde 600.000 kayıt var. Bu bir üst/alt tipi ilişkide bir 2 tablosundaki (JoinTable) üzerinden kendi üzerine katılır:SOL JOIN INNER JOIN

SELECT Child.ID, Parent.ID 
FROM  MainTable 
AS  Child 
JOIN  JoinTable 
     ON Child.ID = JoinTable.ID 
JOIN  MainTable 
AS  Parent 
     ON Parent.ID = JoinTable.ParentID 
    AND Parent.SomeOtherData = Child.SomeOtherData 

Ben her çocuk rekor bir üst kaydı ve JoinTable verileri acurate olduğunu olduğunu biliyoruz.

Bu sorguyu çalıştırdığımda, tam anlamıyla çalıştırılacak dakikalar alır. Bir Sol Üyelik kullanarak ana şirkete katılmak Ancak o zaman çalıştırmak için < 1 saniye sürer:

SELECT Child.ID, Parent.ID 
FROM  MainTable 
AS  Child 
JOIN  JoinTable 
     ON Child.ID = JoinTable.ID 
LEFT JOIN MainTable 
AS  Parent 
     ON Parent.ID = JoinTable.ParentID 
    AND Parent.SomeOtherData = Child.SomeOtherData 
WHERE ...[some info to make sure we don't select parent records in the child dataset]... 

Bir INNER JOIN ve LEFT JOIN arasındaki sonuçlarında farkı anlamak. Bu durumda, her çocuğun bir ebeveyni olduğu gibi, tam olarak aynı sonucu döndürüyor. Her iki sorgunun da çalışmasına izin veriyorum, veri kümelerini karşılaştırabilirim ve tam olarak aynıdır.

Neden LEFT JOININNER JOIN'dan çok daha hızlı çalışıyor?


GÜNCELLEME sorgu planları İşaretli ve kullanırken bir iç o Veli veri kümesi ile başlar katılmak. Bir sol birleştirmeyi yaparken, alt veri kümesi ile başlar.

Kullandığı dizinler hepsi aynı.

Her zaman çocukla başlamaya zorlayabilir miyim? Bir sol birleştirme kullanımı, sadece yanlış geliyor.


Benzer sorular daha önce burada soruldu, ancak hiçbiri soruma yanıt vermiyor gibi görünüyor.

örn. INNER JOIN vs LEFT JOIN performance in SQL Server'daki seçilen cevap, Sol Katılmaların her zaman Inner birleşimlerinden daha yavaş olduğunu belirtir. Argüman mantıklı, ama görüyorum ki değil.

+1

Planları kontrol edin. – Blorgbeard

+0

@Blogbeard - bkz. Güncelleme – Greg

cevap

12

Sol katılmak SQL yapmak zorunda kalır çünkü daha küçük birinci seçip katılmak daha hızlı gibi görünüyor Bu daha küçük kayıtlar. Bazı nedenlerden dolayı optimiser bunu doğal olarak yapmak istemiyor.

3 yolu doğru sırayla gerçekleşmesi katılır zorlamak için:

  1. geçici tablo (veya tablo değişkeni) içine ilk veri alt kümesini seçin sonra
  2. Sol katılır
  3. üzerinden birleştirmek (ve Unutmayın ki bu, farklı bir veriyi döndürür çünkü bir iç birleşim değil sol birleşimdir)
  4. FORCE ORDER anahtar sözcüğünü kullanın. Tablo boyutları veya şemaları değiştiğinde, sorgu planının doğru olmayabileceğini unutmayın (bkz. https://dba.stackexchange.com/questions/45388/forcing-join-order)
+1

Bunun çok geç olduğunu biliyorum, ancak veritabanı istatistiklerinin güncel olduğundan emin olmak isteyebilirsiniz. Sorgu eniyileyicisi, göreli tablo boyutları ve katılma sütunlarındaki değer dağılımları hakkında bilgi sahibi değilse, * kötü * sorgu planı kararı verebilir (SQL Server'lar, birlikte çalıştığım tüm veritabanlarının en tutarlı şekilde iyi sorgu iyileştiricisine sahiptir) . İşte konuyla ilgili bir blog girişi: http://blogs.msdn.com/b/buckwoody/archive/2009/08/18/sql-server-best-practices-auto-create-and-auto-update-statistics- en-of-the-the-of-the-time.aspx – Curt

+0

fikir için teşekkürler. istatistikleri kontrol etmiştik ve güncel olduklarını biliyorum – Greg

+0

Geç olduğunu biliyorum ama başkasına yardımcı olabilir. Katıldığım tek nokta, Tablo değişken önerisidir. Tablo değişkenleri, tabloda kaç satır olduğuna bakılmaksızın, her zaman tahmini satır sayısı 1'i döndürür. Bu, planı büyük ölçüde çarpıtabilir. Oku http://blogs.msdn.com/b/psssql/archive/2014/08/11/if-you-have-queries-that-use-table-variables-sql-server-2012-sp2-can- help.aspx, 2012 SP2'de –

2

Bunu deneyin. Aynı sonuç, farklı yaklaşım:

SELECT c.ID, p.ID 
FROM 
(SELECT Child.ID, JoinTable.ParentID 
FROM  MainTable 
AS  Child 
JOIN  JoinTable 
     ON Child.ID = JoinTable.ID) AS c 
INNER JOIN 
(SELECT Parent.ID, JoinTable.ID 
FROM  MainTable 
AS  Parent 
JOIN  JoinTable 
     ON Parent.ID = JoinTable.ParentID 
    AND Parent.SomeOtherData = Child.SomeOtherData) AS p 
ON c.ParentID = p.ID 

o yardımcı olmazsa, kullanım cte:

;WITH cte AS 
(SELECT Child.ID, JoinTable.ParentID 
FROM  MainTable 
AS  Child 
JOIN  JoinTable 
     ON Child.ID = JoinTable.ID) 
SELECT cte.ID, Parent.ID 
FROM cte INNER JOIN 
MainTable 
AS  Parent 
     ON Parent.ID = cte.ParentID 
    AND Parent.SomeOtherData = cte.SomeOtherData 
+0

CTE yardım etmedi, ancak bir tablo değişkenine zorladı. Başka bir cevap gelmezse ben de onunla koşacağım. – Greg