Sorguyu farklı sözdizimi kullanarak ifade etmek, bazen kümelenmemiş bir dizin kullanma isteğinizi optimize ediciye iletmenize yardımcı olabilir. Aşağıdaki formu size istediğiniz planı verdiğini bulmalısınız:
SELECT
[ID],
[DeviceID],
[IsPUp],
[IsWebUp],
[IsPingUp],
[DateEntered]
FROM [dbo].[Heartbeats]
WHERE
[ID] IN
(
-- Keys
SELECT TOP (1000)
[ID]
FROM [dbo].[Heartbeats]
WHERE
[DateEntered] >= CONVERT(datetime, '2011-08-30', 121)
AND [DateEntered] < CONVERT(datetime, '2011-08-31', 121)
);
Bu planı, kümelenmemiş dizin bir ipucu ile zorlandığında üretilen planla karşılaştırın:
SELECT TOP (1000)
*
FROM [dbo].[Heartbeats] WITH (INDEX(CommonQueryIndex))
WHERE
[DateEntered] BETWEEN '2011-08-30' and '2011-08-31';
Planlar temelde aynıdır (Anahtar Arama, kümelenmiş dizindeki bir aramadan başka bir şey değildir). Her iki plan formu da kümelenmemiş dizinde yalnızca bir arama ve kümelenmiş dizine en fazla 1000 arama gerçekleştirir.
Önemli fark Üst operatör pozisyonundadır. İki arama arasına yerleştirilmiş olan Üst, optimize edicinin iki arama işlemini kümelenmiş dizinin mantıksal olarak eşdeğer taramasıyla değiştirmesini önler. Optimize edici, mantıksal bir planın bölümlerini eşdeğer ilişkisel işlemlerle değiştirerek çalışır. Üst, ilişkisel bir işleç değildir, bu nedenle yeniden yazma, kümelenmiş bir dizin taramasına dönüştürmeyi önler. Optimize edici, Üst operatörü yeniden konumlandırabilseydi, maliyet tahmininin çalışması nedeniyle taramayı arama + aramaya göre tercih ederdi.
Taramaların ve aramaların maliyeti
Çok yüksek bir seviyede, optimizasyonun taramalar ve aramalar için maliyet modeli oldukça basittir: 320 rasgele aramanın 1350 sayfayı bir taramada okumakla aynı olduğunu tahmin eder . Bu, muhtemelen herhangi bir modern I / O sisteminin donanım yeteneklerine çok az benzemektedir, ancak pratik bir model olarak oldukça iyi çalışır.
Model ayrıca, her sorgunun önbellekte zaten veri veya dizin sayfası olmadan başlayacağı varsayılan bir dizi basitleştirici varsayım yapar. Bunun anlamı, her G / Ç'nin fiziksel bir G / Ç ile sonuçlanacağıdır - ancak bu pratikte nadiren olur. Soğuk bir önbellekte bile, önceden getirme ve okuma öncesi, gerekli sayfaların aslında sorgu işlemcisinin ihtiyaç duyduğu anda bellekte olma olasılığı yüksektir.
Başka bir husus, bellekte olmayan bir satır için ilk isteğin tüm sayfanın diskten alınmasına neden olacağıdır. Aynı sayfadaki sonraki satır istekleri büyük olasılıkla fiziksel bir G / Ç'ye neden olmaz. Maliyetleme modeli, bunun gibi bazı etkileri hesaba katmak için mantık içerir, ancak mükemmel değildir.
Tüm bunlar (ve daha fazlası), optimize edicinin muhtemelen olması gerekenden daha erken bir taramaya geçme eğiliminde olduğu anlamına gelir. Rastgele G / Ç, fiziksel bir işlem ortaya çıkarsa 'sıralı' G / Ç'den sadece 'çok daha pahalıdır' - bellekteki sayfalara erişmek gerçekten çok hızlıdır. Fiziksel bir okuma gerektiğinde bile, tarama parçalanma nedeniyle sıralı okumalara yol açmayabilir ve aramalar örüntü esasen sıralı olacak şekilde sıralanabilir. Buna ek olarak modern I / O sistemlerinin (özellikle katı hal) değişen performans karakteristiği ve her şey çok titrek görünmeye başlar.
Satır Hedefleri
Bir Planda bir Üst operatörün bulunması, maliyetlendirme yaklaşımını değiştirir. Optimize edici, bir tarama kullanarak 1000 satır bulmanın büyük olasılıkla tüm kümelenmiş dizinin taranmasını gerektirmeyeceğini bilecek kadar akıllıdır - 1000 satır bulunur bulunmaz durabilir. Üst işleçte 1000 satırlık bir 'satır hedefi' belirler ve satır kaynağından kaç satır gerektiğini (bu durumda bir tarama) tahmin etmek için oradan geri dönmek için istatistiksel bilgileri kullanır. Bu hesaplamanın detaylarını burada yazdım .
Bu yanıttaki resimler SQL Sentry Plan Explorer kullanılarak oluşturuldu .