SQL Server 2014: tutarsız öz katılım kardinalite tahmini için herhangi bir açıklama?


27

SQL Server 2014'te aşağıdaki sorgu planını göz önünde bulundurun:

görüntü tanımını buraya girin

Sorgu planında, bir birleştirme ar.fId = ar.fIdbir 1 satır tahmini verir. Bununla birlikte, bu bir mantıksal tutarsız tahmindir: arsahip 20,608satır ve tek bir ayrı değer fId(doğru istatistik yansıtılır). Bu nedenle, bu birleştirme, satırın ( ~424MMsatırların) tam çarpımını üreterek sorgunun birkaç saat çalışmasına neden olur.

Neden SQL Server'ın istatistiklerle tutarsız olduğu kanıtlanan bir tahminle karşı karşıya geldiğini anlamakta zorlanıyorum. Herhangi bir fikir?

İlk soruşturma ve ek detay

Paul'un buradaki cevabına dayanarak, hem ortak hem de kardinaliteyi tahmin etmek için SQL 2012 ve SQL 2014 buluşsal bulgularının, iki özdeş histogramın karşılaştırılması gereken bir durumu kolayca idare etmesi gerektiği görülüyor.

İz bayrağı 2363'ün çıktısıyla başladım, ancak bunu kolayca anlayamadım. Aşağıdaki SQL Server için histogramlar karşılaştıran anlamına pasajını mu fIdve bIdbir tek o kullanımlarını katılmak seçiciliğini tahmin etmek için fId? Eğer öyleyse, bu açıkça doğru olmaz. Yoksa izleme bayrağı çıktısını yanlış mı okuyorum?

Plan for computation:
  CSelCalcExpressionComparedToExpression( QCOL: [ar].fId x_cmpEq QCOL: [ar].fId )
Loaded histogram for column QCOL: [ar].bId from stats with id 3
Loaded histogram for column QCOL: [ar].fId from stats with id 1
Selectivity: 0

Tam repro betiğine dahil olan ve bu sorguyu milisaniyeye indiren birkaç geçici çözüm bulduğumu unutmayın. Bu soru davranışı anlama, gelecekteki sorgularda nasıl önlenebileceği ve bunun Microsoft ile doldurulması gereken bir hata olup olmadığını belirlemeye odaklanmıştır.

İşte tam bir repro betiği , işte izleme bayrağı 2363'ün tam çıktısı ve işte tam betiği açmadan hızlıca bakmak istemeniz durumunda sorgu ve tablo tanımları:

WITH cte AS (
    SELECT ar.fId, 
        ar.bId,
        MIN(CONVERT(INT, ar.isT)) AS isT,
        MAX(CONVERT(INT, tcr.isS)) AS isS
    FROM  #SQL2014MinMaxAggregateCardinalityBug_ar ar 
    LEFT OUTER JOIN #SQL2014MinMaxAggregateCardinalityBug_tcr tcr
        ON tcr.rId = 508
        AND tcr.fId = ar.fId
        AND tcr.bId = ar.bId
    GROUP BY ar.fId, ar.bId
)
SELECT s.fId, s.bId, s.isS, t.isS
FROM cte s 
JOIN cte t 
    ON t.fId = s.fId 
    AND t.isT = 1

CREATE TABLE #SQL2014MinMaxAggregateCardinalityBug_ar (
    fId INT NOT NULL,
    bId INT NOT NULL,
    isT BIT NOT NULL
    PRIMARY KEY (fId, bId)
)

CREATE TABLE #SQL2014MinMaxAggregateCardinalityBug_tcr (
    rId INT NOT NULL,
    fId INT NOT NULL,
    bId INT NOT NULL,
    isS BIT NOT NULL
    PRIMARY KEY (rId, fId, bId, isS)
)

Yanıtlar:


23

Neden SQL Server'ın istatistiklerle tutarsız olduğu kanıtlanan bir tahminle karşı karşıya geldiğini anlamakta zorlanıyorum.

Tutarlılık

Genel bir tutarlılık garantisi yoktur. Tahminler, farklı istatistiksel yöntemler kullanılarak, farklı zamanlarda farklı (ancak mantıksal olarak eşdeğer) alt ağaçlarda hesaplanabilir.

Bu iki öz alt gruba katılmanın, çapraz ürün üretmesi gerektiğini söyleyen mantıkla ilgili yanlış bir şey yoktur, ancak akıl yürütme seçiminin diğerlerinden daha sağlam olduğunu söyleyen hiçbir şey yoktur.

İlk tahmin

Özel bir durumda, birleştirme için başlangıç önem düzeyi tahmini iki alt alt ağaçta gerçekleştirilmez . O sırada ağaç şekli:

  LogOp_Join
     LogOp_GbAgg
        LogOp_LeftOuterJoin
           LogOp_Get TBL: ar
           LogOp_Select
              LogOp_Get TBL: tcr
              ScaOp_Comp x_cmpEq
                 ScaOp_Identifier [tcr] .rId
                 ScaOp_Const Değeri = 508
           ScaOp_Logical x_lopAnd
              ScaOp_Comp x_cmpEq
                 ScaOp_Identifier [ar] .fId
                 ScaOp_Identifier [tcr] .fId
              ScaOp_Comp x_cmpEq
                 ScaOp_Identifier [ar] .bId
                 ScaOp_Identifier [tcr] .bId
        AncOp_PrjList 
           AncOp_PrjEl Expr1003 
              ScaOp_AggFunc stopMax
                 ScaOp_Convert int
                    ScaOp_Identifier [tcr] .isS
     LogOp_Select
        LogOp_GbAgg
           LogOp_LeftOuterJoin
              LogOp_Get TBL: ar
              LogOp_Select
                 LogOp_Get TBL: tcr
                 ScaOp_Comp x_cmpEq
                    ScaOp_Identifier [tcr] .rId
                    ScaOp_Const Değeri = 508
              ScaOp_Logical x_lopAnd
                 ScaOp_Comp x_cmpEq
                    ScaOp_Identifier [ar] .fId
                    ScaOp_Identifier [tcr] .fId
                 ScaOp_Comp x_cmpEq
                    ScaOp_Identifier [ar] .bId
                    ScaOp_Identifier [tcr] .bId
           AncOp_PrjList 
              AncOp_PrjEl Expr1006 
                 ScaOp_AggFunc stopMin
                    ScaOp_Convert int
                       ScaOp_Identifier [ar] .isT
              AncOp_PrjEl Expr1007 
                 ScaOp_AggFunc stopMax
                    ScaOp_Convert int
                       ScaOp_Identifier [tcr] .isS
        ScaOp_Comp x_cmpEq
           ScaOp_Identifier Expr1006 
           ScaOp_Const Değeri = 1
     ScaOp_Comp x_cmpEq
        ScaOp_Identifier QCOL: [ar] .fId
        ScaOp_Identifier QCOL: [ar] .fId

İlk katılmak giriş bir unprojected agrega uzakta basitleştirilmiş etti ve ikinci giriş yüklemi vardır katılmak t.isT = 1nerede bunun altında itilir t.isTolduğunu MIN(CONVERT(INT, ar.isT)). Buna rağmen, isTyüklem için seçicilik hesaplaması CSelCalcColumnInIntervalhistogramda kullanılabilir:

  CSelCalcColumnInInterval
      Sütun: COL: Expr1006 

QCOL sütunu için yüklenen histogram: kimliği 3 olan istatistiklerden [ar] .isT

Seçicilik: 4.85248e-005

İstatistikler koleksiyonu oluşturuldu: 
  CStCollFilter (ID = 11, CARD = 1)
      CStCollGroupBy (ID = 10, CARD = 20608)
          CStCollOuterJoin (ID = 9, CARD = 20608 x_jtLeftOuter)
              CStCollBaseTable (ID = 3, CARD = 20608 TBL: ar)
              CStCollFilter (ID = 8, CARD = 1)
                  CStCollBaseTable (ID = 4, CARD = 28 TBL: tcr)

Bu doğru tahminle (doğru) 20,608 satırın 1 satıra indirgenmesi beklenir.

Tahmine katıl

Şimdi soru, diğer birleştirme girişinden 20,608 satırının bu satırla nasıl eşleşeceğini soruyor:

  LogOp_Join
      CStCollGroupBy (ID = 7, CARD = 20608)
          CStCollOuterJoin (ID = 6, CARD = 20608 x_jtLeftOuter)
              ...

      CStCollFilter (ID = 11, CARD = 1)
          CStCollGroupBy (ID = 10, CARD = 20608)
              ...

      ScaOp_Comp x_cmpEq
          ScaOp_Identifier QCOL: [ar] .fId
          ScaOp_Identifier QCOL: [ar] .fId

Birleşmeyi genel olarak tahmin etmenin çeşitli yolları vardır. Örneğin şunları yapabiliriz:

  • Her alt ağaçtaki her plan operatöründe yeni histogramlar türetin, birleştirmeye hizalayın (gerektiği şekilde basamak değerleri girin) ve nasıl eşleştiğini görün; veya
  • Histogramların daha basit bir 'kaba' hizalamasını yapın (adım adım değil, minimum ve maksimum değerler kullanarak); veya
  • Yalnızca birleştirme sütunları için ayrı seçimler hesaplayın (temel tablodan ve filtrelemeden), daha sonra birleştirme olmayan yüklemlerin seçicilik efektini ekleyin.
  • ...

Kullanılan kardinalite tahmincisine ve bazı sezgisellere bağlı olarak, bunlardan herhangi biri (veya bir çeşitlemesi) kullanılabilir. Daha fazla bilgi için bkz. Sorgu Planlarınızı SQL Server 2014 Kardinalite Tahmincisi ile En İyileştirme .

Hata?

Şimdi, soruda belirtildiği gibi, bu durumda 'basit' tek sütunlu birleştirme (açık fId) CSelCalcExpressionComparedToExpressionhesap makinesini kullanır :

Hesaplamayı planla:

  CSelCalcExpressionComparedToExpression [ar] .fId x_cmpEq [ar] .fId

QCOL sütunu için yüklenen histogram: [ar] .bId, id 2 bulunan istatistiklerden.
QCOL sütunu için yüklenen histogram: 1 numaralı istatistiklerden [ar] .fId

Seçicilik: 0

Bu hesaplama, 20,608 satırının 1 filtrelenmiş satırla birleştirilmesinin sıfır seçiciliğe sahip olacağını değerlendirir: hiçbir satır eşleşmez (son planlarda bir satır olarak bildirilir). Bu yanlış mı? Evet, muhtemelen yeni CE'de bir hata var. Biri 1 satırın tüm satırlarla veya hiçbiriyle eşleşmeyeceğini iddia edebilir, bu nedenle sonuç makul olabilir, ancak aksi takdirde inanmak için sebep olabilir.

Detaylar aslında oldukça zordur, ancak tahminin fIdfiltrenin seçiciliği tarafından değiştirilmiş, 20608 * 20608 * 4.85248e-005 = 20608satırlar vererek filtrelenmemiş histogramlara dayanması beklentisi oldukça makul.

Bu hesaplamayı takiben hesap makinesi kullanarak anlamına gelecektir CSelCalcSimpleJoinWithDistinctCountsyerine CSelCalcExpressionComparedToExpression. Bunu yapmanın belgelenmiş bir yolu yoktur, ancak merak ediyorsanız, belgelenmemiş izleme bayrağı 9479'u etkinleştirebilirsiniz:

9479 planı

Son birleşmenin iki tek satırlı girişten 20,608 satır ürettiğini, ancak bunun sürpriz olmamasını unutmayın. Orijinal CE tarafından TF 9481 uyarınca üretilen aynı plandır.

Ayrıntıların aldatıcı (ve araştırılması zaman alıcı) olduğunu belirtmiştim, ancak söyleyebildiğim kadarıyla, sorunun kök nedeni, rId = 508sıfır seçiciliği olan yüklem ile ilişkili . Bu sıfır tahmini normal şekilde bir satıra yükseltilir; bu, giriş ağacındaki düşük tahminleri hesaba katması durumunda söz konusu katılımcının sıfır seçicilik tahminine katkıda bulunur gibi görünmektedir (bu nedenle istatistikleri yükleme bId).

Dış birleştirmenin sıfır-sıralı bir iç-taraf tahmini tutmasına izin vermek (bir sıraya yükseltmek yerine) (böylece tüm dış satırlar kalifiye olur) her iki hesap makinesinde de 'hatasız' birleştirme tahmini verir. Bunu keşfetmekle ilgileniyorsanız, belgelenmemiş izleme bayrağı 9473'tür (yalnız):

9473 planı

Birleştirme kardinalite tahmininin davranışı, CSelCalcExpressionComparedToExpressionbaşka bir belgelenmemiş varyasyon bayrağıyla birlikte “bId” ı hesaba katmayacak şekilde de değiştirilebilir (9494). Bütün bunlardan bahsediyorum çünkü böyle şeylere ilgi duyduğunuzu biliyorum; Bir çözüm sundukları için değil. Sorunu Microsoft'a bildirene kadar ve onlar (ya da değil) ele alınana kadar sorguyu farklı bir şekilde ifade etmek, muhtemelen en iyi yoldur. Davranışın kasıtlı olup olmamasına bakılmaksızın, regresyon hakkında duymak isterler.

Son olarak, reprodüksiyon senaryosunda belirtilen bir şeyi daha düzenlemek için: Filtrenin soru planındaki son konumu GbAggAfterJoinSel, birleştirme çıktısı çok küçük olduğundan, toplama ve filtreyi birleştirme üstünde hareket ettiren maliyet tabanlı bir araştırmanın sonucudur. satır sayısı. Filtre, beklendiği gibi başlangıçta birleşimin altındaydı.

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.