Bu benzer sorgular neden farklı optimizasyon aşamaları kullanıyor (işlem işleme ile hızlı plan arasında)?


12

Bu bağlantı öğesindeki örnek kod

Nerede bir hata gösterir

SELECT COUNT(*)
FROM   dbo.my_splitter_1('2') L1
       INNER JOIN dbo.my_splitter_1('') L2
         ON L1.csv_item = L2.csv_item

Doğru sonuçları verir. Ancak aşağıdakiler yanlış sonuçlar döndürür (2014'te yeni Kardinalite Tahmincisi'ni kullanarak)

SELECT
    (SELECT COUNT(*)
    FROM dbo.my_splitter_1('2') L1
     INNER JOIN dbo.my_splitter_1('') L2
        ON L1.csv_item = L2.csv_item)

L2 için sonuçları ortak bir alt ifade makarasına yanlış yükledikten sonra L1 sonucu için sonucu tekrarlar.

İki sorgu arasındaki davranış farkının neden olduğunu merak ettim. İzleme Bayrağı 8675, işe yarayanın girip search(0) - transaction processingbaşarısız olanın girdiğini gösterir search(1) - quick plan.

Bu nedenle, ek dönüşüm kurallarının kullanılabilirliğinin davranıştaki farkın arkasında olduğunu varsayalım ( örneğin, BuildGbApply veya GenGbApplySimple'ı devre dışı bırakmak gibi görünüyor).

Peki, bu çok benzer sorgular için iki plan neden farklı optimizasyon aşamalarıyla karşılaşıyor? Ne okudum itibaren search (0)en az üç tablo gerektirir ve bu durum kesinlikle ilk örnekte karşılanmaz.

Yanıtlar:


7

Her aşamanın giriş koşulları vardır. "En az üç tablo referansına sahip olmak", basit örnekler verirken bahsettiğimiz giriş koşullarından biridir, ancak tek değil.

Genellikle, 0'a katılmak için yalnızca temel birleşimlere ve sendikalara izin verilir; skaler alt sorgular, yarı birleşimler vb. 0 aramasına girişi engeller. Bu aşama gerçekten çok yaygın OLTP tipi sorgu şekilleri içindir. Daha az yaygın olan şeyleri keşfetmek için gereken kurallar etkinleştirilmez. Örnek sorgunuzda skaler bir alt sorgu olduğundan giriş başarısız olur.

Ayrıca tablo referanslarını nasıl saydığınıza da bağlıdır. Bu fonksiyonlarla hiç derinlemesine bakmadım, ama mantık Tablo Değerli Fonksiyonları ve ürettikleri tablo değişkenlerini sayıyor olabilir. Hatta işlevin içindeki tablo başvurusunu sayıyor olabilir - emin değilim; ancak fonksiyonların her yerde zor bir iş olduğunu biliyorum.

İle hata GenGbApplySimpleçirkin. Bu plan şekli her zaman bir olasılıktı, ancak 100 satırlık tablo değişken kardinalitesinin değiştiği kabul edilene kadar maliyet nedenleriyle reddedildi. USE PLANÖrneğin, 2014 öncesi CE'deki sorunlu plan şeklini bir ipucu ile zorlamak mümkündür .

Yeni Connect öğesinin daha önce bildirilen aynı sorunla ilgili olması konusunda haklısınız .

Bir örnek vermek için, aşağıdaki sorgu 0 arama için nitelendirilir:

DECLARE @T AS table (c1 integer NULL);

SELECT U.c1, rn = ROW_NUMBER() OVER (ORDER BY U.c1) 
FROM 
(
    SELECT c1 FROM @T AS T
    UNION
    SELECT c1 FROM @T AS T
    UNION
    SELECT c1 FROM @T AS T
) AS U;

Skaler alt sorguyu dahil etmek için küçük bir değişiklik yapmak, doğrudan arama 1'e gitmek anlamına gelir:

DECLARE @T AS table (c1 integer NULL);

SELECT U.c1, rn = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -- Changed!
FROM 
(
    SELECT c1 FROM @T AS T
    UNION
    SELECT c1 FROM @T AS T
    UNION
    SELECT c1 FROM @T AS T
) AS U;
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.