SQL Server'da bağımlı dış birleşimleri iç içe mi yerleştirmeliyim?


9

Bu konuda karışık bilgiler duydum ve kanonik ya da uzman görüşünü umuyorum.

LEFT OUTER JOINHer biri sonuncuya bağımlı olan birden fazla s varsa, onları iç içe yerleştirmek daha mı iyi?

Bir yapmacık Örneğin, JOINhiç MyParentbağlıdır JOINiçin MyChild: http://sqlfiddle.com/#!3/31022/5

SELECT
    {columns}
FROM
    MyGrandChild AS gc
LEFT OUTER JOIN
    MyChild AS c
        ON c.[Id] = gc.[ParentId]
LEFT OUTER JOIN
    MyParent AS p
        ON p.[id] = c.[ParentId]

resim açıklamasını buraya girin

Http://sqlfiddle.com/#!3/31022/7 ile karşılaştırıldığında

SELECT
    {columns}
FROM
    MyGrandChild AS gc
LEFT OUTER JOIN
    (
    MyChild AS c            
    LEFT OUTER JOIN
        MyParent AS p
            ON p.[id] = c.[ParentId]
    )
    ON c.[Id] = gc.[ParentId]

resim açıklamasını buraya girin

Yukarıda gösterildiği gibi, bunlar SS2k8'de farklı sorgu planları üretir


Yuvalanmış birleştirmeleri kullanmayı seviyorum: michaeljswart.com/2012/09/when-i-use-nested-joins Yine de bir stil meselesi olabilir.
Michael J Swart

Blogunuza yalnızca bağımlı olduğunda görüşmek görünmektedir @MichaelJSwart JOINbir olduğunuINNER JOIN
Matta

1
"Daha iyi" yi nasıl tanımlamak istersiniz? Şahsen, ilk okunması daha kolay buluyorum - aklım ilişkiyi tersine çevirmeye çalışırken geri dönmüyor. Having ON ... ONaralıksız (parantez ya da değil) iki kez çok karıştırıyor.
Aaron Bertrand

4
Bir şey yapmanın iki yolu arasında hiçbir performans farkı bulamadığımda, kendime sorduğum bir sonraki soru: Bu gece bir otobüse çarptıysam veya piyangoyu kazanırsam, hangi sürüm yarın kodumu devralan tarafından en kolay anlaşılır ve korunursa ?
Aaron Bertrand

1
use planAma tersi birinci, ikinci sorgu planını nakli sırasında ipucu çalışır.
Martin Smith

Yanıtlar:


3

Bu kesinlikle kanonik bir cevap değil ama SQL Fiddle'da gösterilen iç içe döngüler sorgu planları için planın USE PLANipucu kullanımı ile Sorgu 2'den Sorgu 1'e uygulanmasının mümkün olduğunu fark ettim ama ters işlem girişiminde başarısız oluyor

Sorgu işlemcisi sorgu planı üretemedi çünkü KULLANIM PLANI ipucu sorgu için yasal olduğu doğrulanamayan bir plan içeriyor. KULLANIM PLANI ipucunu kaldırın veya değiştirin. En iyi başarılı plan zorlama olasılığı için, KULLANIM PLANI ipucunda sağlanan planın aynı sorgu için SQL Server tarafından otomatik olarak oluşturulduğundan emin olun.

Optimize edici dönüşüm kuralının devre dışı bırakılması, ReorderLOJN daha önce başarılı olan plan ipucunun da başarılı olmasını önler.

Veri gösterileri büyük miktarlarda deneme SQL Server dönüşüm kesinlikle yetenekli olduğu (A LOJ B) LOJ Ciçin A LOJ (B LOJ C)doğal olarak hem ama tersi doğru olduğuna dair herhangi bir kanıt görmedik.

İlk sorgunun ikinciden daha iyi performans gösterdiği çok tartışmalı bir durum

DROP TABLE  MyGrandChild , MyChild,  MyParent

CREATE TABLE MyParent
(Id int)

CREATE TABLE MyChild
(Id int PRIMARY KEY
,ParentId int,
Filler char(8000) NULL)

CREATE TABLE MyGrandChild
(Id int
,ParentId int)

INSERT INTO MyChild
                      (Id, ParentId)
SELECT TOP (100000) ROW_NUMBER() OVER (ORDER BY @@SPID),
                     ROW_NUMBER() OVER (ORDER BY @@SPID)    
FROM master..spt_values  v1, master..spt_values                  

INSERT INTO MyGrandChild
                      (Id, ParentId)
OUTPUT INSERTED.Id INTO MyParent
SELECT TOP (3000) Id, Id AS ParentId
FROM MyChild
ORDER BY Id

SET STATISTICS IO ON;
SET STATISTICS TIME ON;

SELECT gc.Id       AS gcId,
       gc.ParentId AS gcpId,
       c.Id        AS cId,
       c.ParentId  AS cpId,
       p.Id        AS pId
FROM   MyGrandChild AS gc
       LEFT OUTER JOIN MyChild AS c
         ON c.[Id] = gc.[ParentId]
       LEFT OUTER JOIN MyParent AS p
         ON p.[Id] = c.[ParentId]

SELECT gc.Id       AS gcId,
       gc.ParentId AS gcpId,
       c.Id        AS cId,
       c.ParentId  AS cpId,
       p.Id        AS pId
FROM   MyGrandChild AS gc
       LEFT OUTER JOIN( MyChild AS c
                        LEFT OUTER JOIN MyParent AS p
                          ON p.[Id] = c.[ParentId])
         ON c.[Id] = gc.[ParentId] 

Hangi planlar verir

resim açıklamasını buraya girin

Benim için Sorgu 1, Sorgu 2 için 108 ms'ye karşı 1,163 ms'lik bir zamana sahipti.

Sorgu 1

Table 'Worktable'. Scan count 0, logical reads 0 
Table 'MyChild'. Scan count 0, logical reads 9196
Table 'MyGrandChild'. Scan count 1, logical reads 7
Table 'MyParent'. Scan count 1, logical reads 5

Sorgu 2

Table 'MyParent'. Scan count 1, logical reads 15000
Table 'MyChild'. Scan count 0, logical reads 9000 
Table 'MyGrandChild'. Scan count 1, logical reads 7

Bu nedenle, ilk ("dürüst olmayan") sözdiziminin potansiyel olarak faydalı olduğu varsayılabilir, çünkü daha fazla potansiyel birleştirme emri dikkate alınmasına izin verir, ancak genel bir kural olarak buna çok güvenecek kadar kapsamlı bir test yapmadım.

Sorgu 2'nin daha iyi performans gösterdiği karşı örnekler bulmak tamamen mümkün olabilir. Her ikisini de deneyin ve yürütme planlarına bakın.


-1

"İç İçe Katılma" adı verilen böyle bir JOIN Türü yoktur. JOIN yazmanın bir başka çeşidi de okunabilirlik kolaylığı amacıyla olabilir. bunları yalnızca anlama amacıyla bir "Alt Sorgu" olarak görebilirsiniz.

kod okunabilirliği konusunda daha fazla endişe duyuyorsanız, benim almam, kişinin neyle görüşülebileceğinin seçimi.

Sorgunun performansıyla ilgili endişeleriniz varsa ve sorguda "JOIN ORDER" ipucunu kullanmıyorsanız, sorgunun "İç İçe Katılma" veya Tüm "Dış Katılma" ile yazılması önemli değildir. SQL Server, iki tabloya ve / veya sonuca katılma maliyetine dayalı olarak sipariş verir. SQL Server, JOIN sadece iki veri kümesi arasında aynı anda yapar.

aslında, SQL sunucusunun ikinci bölümü yapmaya karar vermesi durumunda ikinci şekilde "iç içe birleştirme", "MyChild AS c SOL DIŞ DIŞ GİRİŞİM MyParent AS p ON p. [id] = c. [ParentId]" ile birleştiğini ve bu tablonun gerçekleştiğini hayal edin. SONRAKİ SOL BİRLEŞTİRME'de atacak satırlara sahip olmak. bu durumda SQL sunucusu OUTER JOIN'i bu ikisini yapmak ve bu sonucu bir sonraki JOIN'e geçirmek için gereksiz kaynaklar harcadı.

burada uygun şekilde sorulan ve cevaplanan benzer sorulara da bakabilirsiniz. 'İç içe katılma' sözdizimini anlama


1
Öyleyse neden FORCE JOIN ORDERipucu kullanmadan farklı sorgu planları üretiyorlar ?
Matthew

Bu ipucu olmadan, JOIN siparişini garanti edemeyiz ve bunu kanıtlayan farklı yürütme planını gördüğünüz gibi. örneğin ilk şekilde "tüm Outer Join kullanarak" SQL sunucusu bu ikisinden birini yapıyor olabilir. önce "MyChild + MyGrandChild" ve ardından "MyParent" e KATILIN. Veya önce "MyChild + MyParent" ve ardından "MyGrandChild" e KATILIN.
Anup Shah
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.