ÇAPRAZ UYGULAMA dış birleşmeyi üretir


17

Bölüm üzerinde farklı SQL sayma cevabında Erik Darling bu kodu eksikliği için çalışmak için gönderdi COUNT(DISTINCT) OVER ():

SELECT      *
FROM        #MyTable AS mt
CROSS APPLY (   SELECT COUNT(DISTINCT mt2.Col_B) AS dc
                FROM   #MyTable AS mt2
                WHERE  mt2.Col_A = mt.Col_A
                -- GROUP BY mt2.Col_A 
            ) AS ca;

Sorgu kullanımları CROSS APPLY(değil OUTER APPLY) yani neden bir orada dış yerine yürütülmesi planında katılmak katılmak?

resim açıklamasını buraya girin

Ayrıca neden maddeye göre gruptan vazgeçmek içsel bir birleşmeyle sonuçlanır?

resim açıklamasını buraya girin

Verilerin önemli olduğunu düşünmüyorum ama kevinwhat tarafından verilen sorudan kopyalanıyorum:

create table #MyTable (
Col_A varchar(5),
Col_B int
)

insert into #MyTable values ('A',1)
insert into #MyTable values ('A',1)
insert into #MyTable values ('A',2)
insert into #MyTable values ('A',2)
insert into #MyTable values ('A',2)
insert into #MyTable values ('A',3)

insert into #MyTable values ('B',4)
insert into #MyTable values ('B',4)
insert into #MyTable values ('B',5)

Yanıtlar:


23

özet

SQL Server, doğru birleştirmeyi (iç veya dış) kullanır ve uygula ve birleştir arasında iç çeviriler gerçekleştirirken, özgün sorgunun tüm anlamlarını onurlandırmak için gerektiğinde projeksiyonlar ekler .

Planlardaki farklılıkların tümü , SQL Server'da bir group by cümlesi olan ve olmayan agregaların farklı semantiği ile açıklanabilir .


ayrıntılar

Katıl ve Uygula

Bir başvuru ve bir katılma arasında ayrım yapabilmemiz gerekir :

  • Uygulamak

    İç (alt) giriş uygulamak mevcut dış sıra tarafından sağlanan bir veya daha fazla iç yan parametre değerleri ile, dış (alt), girişin her satır için çalıştırılır. Genel sonucu uygulanır parametreli iç yan infaz tarafından üretilen tüm satırları kombinasyonu (her birlik) 'dir. Parametreler araçlarının varlığı geçerlidir bazen katılmak korelasyon olarak anılır.

    Bir uygula hep tarafından icra planlarında uygulanan İç içe döngü operatör. İşleç, birleşim tahminlerinden ziyade bir Dış Referanslar özelliğine sahip olacaktır . Dış referanslar, halkanın her bir yinelemesinde dış taraftan iç tarafa geçirilen parametrelerdir.

  • Katılmak

    Birleştirme, birleştirme işlecindeki birleştirme yüklemesini değerlendirir. Birleştirme genellikle SQL Server'daki Hash Match , Merge veya Nested Loops operatörleri tarafından uygulanabilir .

    Tüm İç içe döngü seçilmiş bir mesafede, bu ayırt edilebilir geçerli olmaması ile dış Kaynaklar (ve genellikle varlığı yüklemi birleştirme). Bir iç giriş katılması dış girişten hiç referanslar değerleri - iç taraf hala her dış satır için bir kez gerçekleştirilir, ancak iç yan infaz mevcut dış sıra herhangi bir değerlerine bağlı değildir.

Daha fazla ayrıntı için gönderime bakın Nested Loops'a karşı Uygula'ya katılın .

... neden bir var dış yerine yürütülmesi planında katılmak katılmak?

Dış birleştirme, optimize edici , daha ucuz bir birleştirme tabanlı plan bulup bulamayacağını görmek için bir uygulamayı bir birleşime (adlı bir kural kullanarak ApplyHandler) dönüştürdüğünde ortaya çıkar . Bir dış olmak için katılmak için gereklidir katılmak doğruluğu zaman geçerli bir içerdiği sayıl agrega . Bir iç birleşimin , orijinalin uygulayacağımızla aynı sonuçları üreteceği garanti edilmez .

Skaler ve Vektör Kümeleri

  • İlgili GROUP BYcümlesine sahip olmayan bir toplama , skaler bir toplamadır.
  • Karşılık gelen bir cümleye sahip bir toplama GROUP BY, bir vektör toplamadır.

SQL Server'da, bir ölçekleme toplamı, birleştirilecek satır verilmemiş olsa bile, her zaman bir satır oluşturur. Örneğin, COUNTsatır içermeyen skaler agrega sıfırdır. Satır içermeyen bir vektör COUNT toplamı boş kümedir (hiç satır yok).

Aşağıdaki oyuncak sorguları farkı göstermektedir. Skaler ve Vektör Agregaları ile Eğlenceli makalemde skaler ve vektör agregaları hakkında daha fazla bilgi bulabilirsiniz .

-- Produces a single zero value
SELECT COUNT_BIG(*) FROM #MyTable AS MT WHERE 0 = 1;

-- Produces no rows
SELECT COUNT_BIG(*) FROM #MyTable AS MT WHERE 0 = 1 GROUP BY ();

db <> keman demosu

Dönüştürme katılmak için geçerlidir

Daha önce , orijinal uygulama bir skaler agrega içerdiğinde , birleşmenin doğruluk için bir dış birleşim olması gerektiğini belirtmiştim . Bu durumun neden ayrıntılı olduğunu göstermek için, soru sorgusunun basitleştirilmiş bir örneğini kullanacağım:

DECLARE @A table (A integer NULL, B integer NULL);
DECLARE @B table (A integer NULL, B integer NULL);

INSERT @A (A, B) VALUES (1, 1);
INSERT @B (A, B) VALUES (2, 2);

SELECT * FROM @A AS A
CROSS APPLY (SELECT c = COUNT_BIG(*) FROM @B AS B WHERE B.A = A.A) AS CA;

Sütun için doğru sonuç cise sıfırdır , çünkü COUNT_BIGbir olduğunu sayıl agrega. Bu uygulama sorgusunu birleştirme formuna çevirirken SQL Server, T-SQL'de ifade edilirse aşağıdakine benzer bir iç alternatif oluşturur:

SELECT A.*, c = COALESCE(J1.c, 0)
FROM @A AS A
LEFT JOIN
(
    SELECT B.A, c = COUNT_BIG(*) 
    FROM @B AS B
    GROUP BY B.A
) AS J1
    ON J1.A = A.A;

Uygulamayı ilişkisiz bir birleşim olarak yeniden yazmak için GROUP BY, türetilmiş tabloya bir tane eklememiz gerekir (aksi takdirde Abirleştirilecek sütun olamaz ). Birleşim bir dış birleşim olmalıdır, böylece tablodaki her satır @Açıktıda bir satır üretmeye devam eder. Birleştirme yüklemesi true olarak değerlendirilmediğinde, sol birleştirme bir NULLfor sütunu üretecektir c. Yani NULLihtiyaçları tarafından sıfıra Çevrilecek COALESCEbir doğru dönüşümü tamamlamak için geçerlidir .

Aşağıdaki demo, hem dış birleştirmenin hem de orijinal uygulama sorgusuyla birleştirmeCOALESCE kullanarak aynı sonuçları üretmenin gerekli olduğunu gösterir :

db <> keman demosu

İle GROUP BY

... grubu maddeye göre uncomment etmek neden içsel bir birleşmeyle sonuçlanır?

Basitleştirilmiş örneğe devam etmek, ancak aşağıdakileri eklemek GROUP BY:

DECLARE @A table (A integer NULL, B integer NULL);
DECLARE @B table (A integer NULL, B integer NULL);

INSERT @A (A, B) VALUES (1, 1);
INSERT @B (A, B) VALUES (2, 2);

-- Original
SELECT * FROM @A AS A
CROSS APPLY 
(SELECT c = COUNT_BIG(*) FROM @B AS B WHERE B.A = A.A GROUP BY B.A) AS CA;

COUNT_BIGŞimdi ise vektör boş giriş kümesi için doğru sonuç artık sıfır olduğu öyledir, agrega hiç hiçbir satır . Başka bir deyişle, yukarıdaki ifadeleri çalıştırmak çıktı üretmez.

Dan çeviri yaparken bu semantik onuruna çok daha kolaydır uygulamak için katılmak beri, CROSS APPLYdoğal olarak hiçbir iç yan satırları oluşturan her türlü dış sırayı reddeder. Bu nedenle, artık ekstra ifade projeksiyonu olmadan artık bir iç birleşimi güvenle kullanabiliriz:

-- Rewrite
SELECT A.*, J1.c 
FROM @A AS A
JOIN
(
    SELECT B.A, c = COUNT_BIG(*) 
    FROM @B AS B
    GROUP BY B.A
) AS J1
    ON J1.A = A.A;

Aşağıdaki demo, iç birleşim yeniden yazmasının, orijinalin vektör toplamıyla uygulandığıyla aynı sonuçları verdiğini göstermektedir:

db <> keman demosu

Optimize edici, hızlı bir şekilde ucuz bir birleştirme planı bulduğu için (yeterince iyi plan bulundu) küçük tablo ile birleştirme iç birleşimi seçer . Maliyete dayalı iyileştirici, bir döngüye birleştirme veya yeniden öngörü ipucu kullanıldığında burada olacağı için, birleştirmeyi yeniden bir uygulamaya yeniden yazmaya devam edebilir - belki de daha ucuz bir uygulama planı bulmak - ancak bu durumda çabaya değmez.

notlar

Basitleştirilmiş örnekler, anlamsal farklılıkları daha net göstermek için farklı içeriklere sahip farklı tablolar kullanır.

Optimize edicinin, kendiliğinden birleştirme ile eşleşmeyen (birleşmeyan) satırlar üretememe konusunda mantık yürütmesi gerektiği iddia edilebilir, ancak bugün bu mantığı içermez. Aynı tabloya bir sorguda birden çok kez erişmenin, yalıtım düzeyine ve eşzamanlı etkinliğe bağlı olarak genel olarak aynı sonuçları üreteceği garanti edilmez.

Optimize edici bu anlambilim ve uç durumlar için endişe duymaktadır, bu yüzden yapmanız gerekmez.


Bonus: İç Başvuru Planı

SQL Server edebilir bir iç üretmek uygulamak planı (bir iç değil katılmak sadece maliyet nedenleriyle değil seçerse, örneğin sorgu için bir plan!). Soruda gösterilen dış birleştirme planının maliyeti, dizüstü bilgisayarımın SQL Server 2017 örneğinde 0.02898 birimdir.

Belgelendirilmemiş ve desteklenmeyen izleme bayrağı 9114'ü (devre dışı bırakan vb.) Kullanarak yalnızca örnekleme amacıyla bir uygulama (ilişkilendirilmiş birleştirme) planı uygulayabilirsinizApplyHandler :

SELECT      *
FROM        #MyTable AS mt
CROSS APPLY 
(
    SELECT COUNT_BIG(DISTINCT mt2.Col_B) AS dc
    FROM   #MyTable AS mt2
    WHERE  mt2.Col_A = mt.Col_A 
    --GROUP BY mt2.Col_A
) AS ca
OPTION (QUERYTRACEON 9114);

Bu, tembel bir dizin makarası ile bir iç içe döngü uygula planı oluşturur. Toplam tahmini maliyet 0.0463983'tür (seçilen plandan daha yüksek):

Endeks Makarası uygulama planı

İç içe döngüler uygulama kullanan yürütme planının , GROUP BYcümlenin varlığına bakılmaksızın "iç birleşim" semantiği kullanılarak doğru sonuçlar verdiğini unutmayın .

Gerçek dünyada, genellikle SQL Server'ın bu seçeneği doğal olarak seçmesini teşvik etmek için başvurunun iç tarafında bir aramayı destekleyecek bir dizinimiz olurdu , örneğin:

CREATE INDEX i ON #MyTable (Col_A, Col_B);

db <> keman demosu


-3

Çapraz Uygula, veriler üzerinde mantıklı bir işlemdir. Bu verileri nasıl alacağınıza karar verirken SQL Server, istediğiniz verileri almak için uygun fiziksel operatörü seçer.

Fiziksel bir uygulama operatörü yoktur ve SQL Server onu uygun ve umarım verimli birleştirme operatörüne çevirir.

Fiziksel operatörlerin bir listesini aşağıdaki bağlantıda bulabilirsiniz.

https://docs.microsoft.com/en-us/sql/relational-databases/showplan-logical-and-physical-operators-reference?view=sql-server-2017

Sorgu iyileştirici, mantıksal operatörlerden oluşan bir ağaç olarak bir sorgu planı oluşturur. Sorgu iyileştirici planı oluşturduktan sonra, sorgu iyileştirici her mantıksal işleç için en verimli fiziksel işleci seçer. Sorgu iyileştirici, hangi fiziksel operatörün mantıksal bir operatör uygulayacağını belirlemek için maliyete dayalı bir yaklaşım kullanır.

Genellikle, mantıksal bir işlem birden çok fiziksel operatör tarafından uygulanabilir. Bununla birlikte, nadir durumlarda, fiziksel bir operatör birden fazla mantıksal işlemi de uygulayabilir.

edit / Görünüşe göre sorunuzu yanlış anladım. SQL sunucusu normalde en uygun operatörü seçecektir. Sorgunuzun, çapraz birleştirmenin kullanıldığı her iki tablonun tüm kombinasyonları için değer döndürmesi gerekmez. Her satır için istediğiniz değeri hesaplamak yeterlidir ki bu da burada yapılır.

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.