Arama neden optimize edici tarafından seçilmiyor?
TL: DR Genişletilmiş hesaplanmış sütun tanımı, optimize edicinin başlangıçta eklemleri yeniden sıralama yeteneğini etkiler. Farklı bir başlangıç noktasıyla, maliyete dayalı optimizasyon optimizerde farklı bir yol izler ve farklı bir nihai plan seçeneğiyle sonuçlanır.
ayrıntılar
En basit sorgular dışındaki herkes için, optimizer olası planların tüm alanı gibi bir şey keşfetmeye çalışmaz. Bunun yerine, makul görünümlü bir başlangıç noktası seçer , ardından makul bir plan bulana kadar bir veya daha fazla arama aşamasında mantıksal ve fiziksel varyasyonları keşfetmek için bütçelenmiş bir çaba harcar.
İki durum için farklı planlar (farklı nihai maliyet tahminleri ile) elde etmenizin ana nedeni, farklı başlangıç noktalarının olmasıdır. Farklı bir yerden başlayarak, optimizasyon farklı bir yerde sona erer (sınırlı sayıda keşif ve uygulama yinelemesinden sonra). Umarım bu oldukça sezgiseldir.
Başlangıç noktası I bahsedilen biraz terimi metinsel temsil dayanmaktadır, ancak değişiklikler bu normalleşmeyi bağlanma ayrıştırma boyunca geçerken iç ağaç gösterimi yapılan ve sorgu derleme basitleştirilmesi aşamaları vardır.
Daha da önemlisi, kesin başlangıç noktası büyük ölçüde optimize edici tarafından seçilen ilk birleşme sırasına bağlıdır . Bu seçim, istatistikler yüklenmeden önce ve herhangi bir kardinalite tahmini türetilmeden önce yapılır. Bununla birlikte, her bir tablodaki toplam kardinalite (satır sayısı), sistem meta verilerinden elde edilmiş olarak bilinir.
İlk birleşme sırası bu nedenle buluşsal yöntemlere dayanır . Örneğin, iyileştirici ağacı daha küçük tabloların daha büyük olanlardan önce birleştirileceği ve iç birleşimler dış birleşimlerin (ve çapraz birleşimlerin) önüne geleceği şekilde yeniden yazmaya çalışır.
Hesaplanan sütunun varlığı, özellikle işlemcinin dış birleşimleri sorgu ağacında aşağı itme yeteneğiyle bu işleme müdahale eder. Bunun nedeni, hesaplanan sütunun birleştirme yeniden sıralaması gerçekleşmeden önce temel ifadesine genişletilmesidir ve bir birleştirmeyi karmaşık bir ifadenin ötesine taşımak, basit bir sütun başvurusunu geçmekten çok daha zordur.
İlgili ağaçlar oldukça büyüktür, ancak açıklamak için hesaplanmamış sütun ilk sorgu ağacı şununla başlar: (üstteki iki dış birleşime dikkat edin)
LogOp_Select
LogOp_Apply (x_jtLeftOuter)
LogOp_LeftOuterJoin
LogOp_NAryJoin
LogOp_LeftAntiSemiJoin
LogOp_NAryJoin
LogOp_GBL'yi al: dbo.table1 (TBL: a4 takma adı)
LogOp_Select
LogOp_Get TBL: dbo.table6 (TBL: a3 takma adı)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a3] .col18
ScaOp_Const TI (varchar collate 53256, Var, Trim, ML = 16)
LogOp_Select
LogOp_GT TBL'si alın: dbo.table1 (TBL: a1 takma adı)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a1] .col2
ScaOp_Const TI (varchar collate 53256, Var, Trim, ML = 16)
LogOp_Select
LogOp_GT TBL'si alın: dbo.table5 (TBL: a2 takma adı)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a2] .col2
ScaOp_Const TI (varchar collate 53256, Var, Trim, ML = 16)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a4] .col2
ScaOp_Identifier QCOL: [a3] .col19
LogOp_Select
LogOp_GT TBL'si alın: dbo.table7 (TBL: a7 takma adı)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a7] .col22
ScaOp_Const TI (varchar collate 53256, Var, Trim, ML = 16)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a4] .col2
ScaOp_Identifier QCOL: [a7] .col23
LogOp_Select
LogOp_Get TBL: table1 (TBL diğer adı: cdc)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [cdc] .col6
ScaOp_Const TI (smallint, ML = 2) XVAR (smallint, Sahip değil, Değer = 4)
LogOp_GT TBL'si alın: dbo.table5 (TBL: a5 takma adı)
LogOp_Get TBL: table2 (diğer ad TBL: cdt)
ScaOp_Logical x_lopAnd
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a5] .col2
ScaOp_Identifier QCOL: [cdc] .col2
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a4] .col2
ScaOp_Identifier QCOL: [cdc] .col2
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [cdt] .col1
ScaOp_Identifier QCOL: [cdc] .col1
LogOp_Get TBL: table3 (TBL takma adı: ahcr)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [ahcr] .col9
ScaOp_Identifier QCOL: [cdt] .col1
Hesaplanan sütun sorgusunun aynı parçası : (dış birleşimin çok daha aşağı olduğunu, genişletilmiş hesaplanmış sütun tanımını ve (iç) birleşim sıralamasındaki diğer bazı küçük farkları not edin)
LogOp_Select
LogOp_Apply (x_jtLeftOuter)
LogOp_NAryJoin
LogOp_LeftAntiSemiJoin
LogOp_NAryJoin
LogOp_GT TBL'si alın: dbo.table1 (TBL: a4 takma adı)
LogOp_Select
LogOp_Get TBL: dbo.table6 (TBL: a3 takma adı)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a3] .col18
ScaOp_Const TI (varchar collate 53256, Var, Trim, ML = 16)
LogOp_Select
LogOp_GT TBL'si alın: dbo.table1 (TBL: a1 takma adı
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a1] .col2
ScaOp_Const TI (varchar collate 53256, Var, Trim, ML = 16)
LogOp_Select
LogOp_GT TBL'si alın: dbo.table5 (TBL: a2 takma adı)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a2] .col2
ScaOp_Const TI (varchar collate 53256, Var, Trim, ML = 16)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a4] .col2
ScaOp_Identifier QCOL: [a3] .col19
LogOp_Select
LogOp_GT TBL'si alın: dbo.table7 (TBL: a7 takma adı)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a7] .col22
ScaOp_Const TI (varchar collate 53256, Var, Trim, ML = 16)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a4] .col2
ScaOp_Identifier QCOL: [a7] .col23
LogOp_Project
LogOp_LeftOuterJoin
LogOp_Join
LogOp_Select
LogOp_Get TBL: table1 (TBL diğer adı: cdc)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [cdc] .col6
ScaOp_Const TI (smallint, ML = 2) XVAR (smallint, Sahip değil, Değer = 4)
LogOp_Get TBL: table2 (diğer ad TBL: cdt)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [cdc] .col1
ScaOp_Identifier QCOL: [cdt] .col1
LogOp_Get TBL: table3 (TBL takma adı: ahcr)
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [ahcr] .col9
ScaOp_Identifier QCOL: [cdt] .col1
AncOp_PrjList
AncOp_PrjEl QCOL: [cdc] .col7
ScaOp_Convert karakter harmanı 53256, Null, Trim, ML = 6
ScaOp_IIF varchar harman 53256, Null, Var, Trim, ML = 6
ScaOp_Comp x_cmpEq
ScaOp_Intrinsic isnumeric
ScaOp_Intrinsic hakkı
ScaOp_Identifier QCOL: [cdc] .col4
ScaOp_Const TI (int, ML = 4) XVAR (int, Sahip Olulmamış, Değer = 4)
ScaOp_Const TI (int, ML = 4) XVAR (int, Sahip Olulmamış, Değer = 0)
ScaOp_Const TI (varchar collate 53256, Var, Trim, ML = 1) XVAR (varchar, Sahip olunan, Değer = Len, Veri = (0,))
ScaOp_Intrinsic alt dize
ScaOp_Const TI (int, ML = 4) XVAR (int, Sahip Olulmamış, Değer = 6)
ScaOp_Const TI (int, ML = 4) XVAR (int, Sahip Olulmamış, Değer = 1)
ScaOp_Identifier QCOL: [cdc] .col4
LogOp_GT TBL'si alın: dbo.table5 (TBL: a5 takma adı)
ScaOp_Logical x_lopAnd
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a5] .col2
ScaOp_Identifier QCOL: [cdc] .col2
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [a4] .col2
ScaOp_Identifier QCOL: [cdc] .col2
İstatistikler yüklenir ve ilk birleştirme sırası ayarlandıktan hemen sonra ağaç üzerinde bir ilk kardinalite tahmini gerçekleştirilir. Birleşimlerin farklı sıralarda olması da bu tahminleri etkiler ve bu nedenle daha sonraki maliyete dayalı optimizasyon sırasında devirme etkisi vardır.
Son olarak, bu bölüm için, ağacın ortasına takılmış bir dış birleştirme olması, maliyete dayalı optimizasyon sırasında bazı yeniden birleştirme kurallarının eşleşmesini önleyebilir.
Bir plan kılavuzu (veya aynı şekilde bir USE PLAN
ipucu - sorgunuz için örnek ) kullanmak , arama stratejisini , sağlanan şablonun genel şekli ve özellikleri tarafından yönlendirilen daha hedefe yönelik bir yaklaşımla değiştirir . İyileştirici açıklıyor olabilir aynı bulmak table1
bir plan kılavuzu veya ipucu kullanıldığında, hem bilgisayarlı ve olmayan hesaplanan sütun şemaları karşı planı ararlar.
Arayışı gerçekleştirmek için farklı bir şey yapıp yapamayacağımız
Bu, yalnızca optimize edici kendi başına kabul edilebilir performans özelliklerine sahip bir plan bulamazsa endişelenmeniz gereken bir şeydir.
Tüm normal ayar araçları potansiyel olarak uygulanabilir. Örneğin, sorguyu daha basit parçalara ayırabilir, kullanılabilir endekslemeyi gözden geçirebilir ve geliştirebilir, yeni istatistikleri güncelleyebilir veya oluşturabilirsiniz ... vb.
Bütün bunlar kardinalite tahminlerini, optimize ediciden alınan kod yolunu ve maliyete dayalı kararları süptil yollarla etkileyebilir.
Sonuçta ipuçlarını (veya bir plan kılavuzunu) kullanmaya başvurabilirsiniz, ancak bu genellikle ideal çözüm değildir.
Yorumlardan ek sorular
Sorgu vb basitleştirmek için en iyi olduğunu kabul ediyorum, ama optimizer optimizasyon ile devam ve aynı sonuca ulaşmak için bir yol (izleme bayrağı) var mı?
Hayır, kapsamlı bir arama yapmak için hiçbir izleme bayrağı yoktur ve bir tane istemezsiniz. Olası arama alanı çok geniştir ve evrenin yaşını aşan derleme süreleri iyi karşılanmaz. Ayrıca, optimizer olası her mantıksal dönüşümü bilmiyor (kimse bilmiyor).
Ayrıca, sütun devam ettiği için neden karmaşık genişleme gerekiyor? Optimize edici neden onu genişletmekten kaçınmıyor, normal bir sütun gibi davranıyor ve aynı başlangıç noktasına ulaşamıyor?
Ek optimizasyon fırsatlarını etkinleştirmek için hesaplanan sütunlar genişletilir (görünümler gibi). Genişletme işlemin ilerleyen bölümlerinde örneğin kalıcı bir sütun veya dizine geri eşleştirilebilir, ancak bu ilk birleştirme sırası sabitlendikten sonra gerçekleşir .