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 = 1
nerede bunun altında itilir t.isT
olduğunu MIN(CONVERT(INT, ar.isT))
. Buna rağmen, isT
yüklem için seçicilik hesaplaması CSelCalcColumnInInterval
histogramda 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
) CSelCalcExpressionComparedToExpression
hesap 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 fId
filtrenin seçiciliği tarafından değiştirilmiş, 20608 * 20608 * 4.85248e-005 = 20608
satırlar vererek filtrelenmemiş histogramlara dayanması beklentisi oldukça makul.
Bu hesaplamayı takiben hesap makinesi kullanarak anlamına gelecektir CSelCalcSimpleJoinWithDistinctCounts
yerine CSelCalcExpressionComparedToExpression
. Bunu yapmanın belgelenmiş bir yolu yoktur, ancak merak ediyorsanız, belgelenmemiş izleme bayrağı 9479'u etkinleştirebilirsiniz:
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 = 508
sı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):
Birleştirme kardinalite tahmininin davranışı, CSelCalcExpressionComparedToExpression
baş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ı.