Bu, maliyet temelli optimizasyon kararının bir kararıdır.
Bu seçimde kullanılan tahmini maliyetler, farklı sütunlardaki değerler arasındaki istatistiksel bağımsızlığı varsaydığı için yanlıştır.
Satır Hedefleri Gone Rogue'de açıklanan ve çift ve tek sayıların negatif korelasyon gösterdiği konuya benzer .
Çoğaltılması kolaydır.
CREATE TABLE dbo.animal(
id int IDENTITY(1,1) NOT NULL PRIMARY KEY,
colour varchar(50) NOT NULL,
species varchar(50) NOT NULL,
Filler char(10) NULL
);
/*Insert 20 million rows with 1% black and 1% swan but no black swans*/
WITH T
AS (SELECT TOP 20000000 ROW_NUMBER() OVER (ORDER BY @@SPID) AS RN
FROM master..spt_values v1,
master..spt_values v2,
master..spt_values v3)
INSERT INTO dbo.animal
(colour,
species)
SELECT CASE
WHEN RN % 100 = 1 THEN 'black'
ELSE CAST(RN % 100 AS VARCHAR(3))
END,
CASE
WHEN RN % 100 = 2 THEN 'swan'
ELSE CAST(RN % 100 AS VARCHAR(3))
END
FROM T
/*Create some indexes*/
CREATE NONCLUSTERED INDEX ix_species ON dbo.animal(species);
CREATE NONCLUSTERED INDEX ix_colour ON dbo.animal(colour);
Şimdi dene
SELECT TOP 10 *
FROM animal
WHERE colour LIKE 'black'
AND species LIKE 'swan'
Bu, aşağıdaki maliyetin altında olduğu planı verir 0.0563167
.
Plan, id
sütundaki iki dizinin sonuçları arasında bir birleştirme birleşimi gerçekleştirebilir . ( Birleştirme daha fazla ayrıntı burada algoritma katılmak ).
Birleştirme birleştirmesi, her iki girişin birleştirme anahtarı tarafından sipariş edilmesini gerektirir.
Kümelenmemiş dizinler sırasıyla (species, id)
ve (colour, id)
sırasıyla sıralanır (benzersiz kümelenmemiş dizinler, her zaman açıkça eklenmezse , anahtarın sonuna eklenen satır konumlandırıcısına sahiptir ). Joker karakterler olmadan yapılan sorgu, eşitlik arayışı içinde species = 'swan'
ve arasında bir eşitlik gerçekleştiriyor colour ='black'
. Her arayış, öndeki sütundan yalnızca bir tam değer elde ettiğinden, eşleşme satırları id
bu plana göre sıralanacaktır .
Sorgu planı operatörleri soldan sağa yürütülür . Sol operatör gelen dönüş isteği sıralar halinde onun çocukları, satırları talebinde ile onların çocukları (vb yaprak düğümleri ulaşıncaya kadar). TOP
10 alındıktan sonra yineleyici onun çocuktan daha fazla satır talep eden duracaktır.
SQL Server, dizinlerde, satırların% 1'inin her yüklem ile eşleştiğini söyleyen istatistiklere sahiptir. Bu istatistiklerin bağımsız olduğunu (yani, pozitif ya da negatif olarak korelasyon göstermediğini) varsaymaktadır, böylece ortalama olarak, ilk tahmini ile eşleşen 1000 satırı işlediğinde, ikincisiyle eşleşen 10'u bulacağını ve çıkabileceğini düşünür. (yukarıdaki plan aslında 1.000 yerine 987'yi gösteriyor ancak yeterince yakın).
Gerçekte, tahminler negatif korelasyon gösterdiği için gerçek plan, 200.000 eşleştirme satırının her bir dizinden işlenmesi gerektiğini ancak bunun bir dereceye kadar azaltıldığını, çünkü birleştirilmiş sıfır sıranın da aslında sıfır aramaya ihtiyaç duyulduğunu göstermektedir.
İle karşılaştırmak
SELECT TOP 10 *
FROM animal
WHERE colour LIKE 'black%'
AND species LIKE 'swan'
Hangi maliyetin altında olduğu planını verir 0.567943
İzleyen joker karakterin eklenmesi şimdi dizin taramasına neden oldu. Planın maliyeti, 20 milyon satırlık masa üzerinde yapılan bir tarama için yine de oldukça düşük.
Ekleme querytraceon 9130
biraz daha bilgi gösterir
SELECT TOP 10 *
FROM animal
WHERE colour LIKE 'black%'
AND species LIKE 'swan'
OPTION (QUERYTRACEON 9130)
SQL Server'ın, yüklem ile eşleşen 10 eşleme bulmadan önce yaklaşık 100.000 satır taraması gerekebileceğini ve satır istemeyi TOP
durdurabildiğini görüyoruz.
Yine bu bağımsızlık varsayımına göre mantıklı geliyor 10 * 100 * 100 = 100,000
Sonunda, bir endeks kesişim planını deneyip zorlayalım
SELECT TOP 10 *
FROM animal WITH (INDEX(ix_species), INDEX(ix_colour))
WHERE colour LIKE 'black%'
AND species LIKE 'swan'
Bu benim için 3.4625 tahmini maliyeti ile paralel bir plan verir
Buradaki ana fark, colour like 'black%'
yüklemin şimdi birden çok farklı renkle eşleşebileceğidir. Bu, o yüklem için eşleşen dizin satırlarının, sırasıyla sıralanmasının garanti edilmediği anlamına gelir id
.
Örneğin, üzerinde dizin arayan like 'black%'
aşağıdaki satırları döndürebilir
+------------+----+
| Colour | id |
+------------+----+
| black | 12 |
| black | 20 |
| black | 23 |
| black | 25 |
| blackberry | 1 |
| blackberry | 50 |
+------------+----+
Her rengin içinde kimlikleri sipariş edilir, ancak farklı renklerde bulunan kimlikleri iyi olmayabilir.
Sonuç olarak, SQL Server artık bir birleştirme birleştirme dizini dizin kesişimi gerçekleştiremez (engelleyen bir sıralama işleci eklemeden) ve bunun yerine karma birleştirme gerçekleştirmeyi seçer. Karma Birleştirme derleme girişini engelliyor, bu nedenle maliyet, eşleşen ilk satırlarda olduğu gibi yalnızca 1000'i taraması gerekeceğini varsaymak yerine, eşleşen tüm satırların derleme girişinden işlenmesi gerektiği gerçeğini yansıtıyor.
Prob girişi bloke edici değildir ve yine de yanlış bir şekilde, bundan 987 satır işledikten sonra problamayı durdurabileceğini tahmin etmektedir.
(Burada, yineleyicileri engellememe ve engelleme hakkında daha fazla bilgi)
Ekstra tahmini satırların artan maliyetleri göz önüne alındığında ve karma kümelenmiş endeks taramasına katılan karma daha ucuz görünüyor.
Elbette pratikte "kısmi" kümelenmiş endeks taraması hiç kısmi değildir ve planları karşılaştırırken varsayılan 100 bin yerine 20 milyon satırın tamamını geçmesi gerekir.
Değerinin arttırılması TOP
(veya tamamen kaldırılması) sonunda CI taramasının kapsaması gerekeceğini tahmin ettiği satır sayısının bu planın daha pahalı görünmesini sağladığı ve endeks kesişim planına geri döndüğü bir devrilme noktasıyla karşılaşır. İki planları arasında Benim için kesilir noktasıdır TOP (89)
vs TOP (90)
.
Sizin için kümelenmiş indeksin genişliğine bağlı olarak farklılık gösterebilir.
TOP
CI taramasını kaldırma ve zorlama
SELECT *
FROM animal WITH (INDEX = 1)
WHERE colour LIKE 'black%'
AND species LIKE 'swan'
88.0586
Örnek masam için makinemde maliyet .
Eğer SQL Server, hayvanat bahçesinin siyah kuğu olmadığını ve sadece 100.000 satır okumak yerine tam bir tarama yapması gerektiğini bilseydi bu plan seçilmezdi.
Ben çoklu kolon istatistikleri denedim animal(species,colour)
ve animal(colour,species)
ve ilgili istatistikleri süzülmüş animal (colour) where species = 'swan'
ancak bunların hiçbiri siyah kuğu var olmayan ve bu kadar ikna etmede TOP 10
tarama 100.000'den fazla satır işlemek gerekir.
Bunun nedeni, SQL Server'ın temelde bir şey ararken, muhtemelen var olduğunu varsaydığı varsayımdan kaynaklanmaktadır.
2008+ 'de, sıra hedeflerini durduran 4138 belgelenmiş bir iz bayrağı vardır . Bunun etkisi, planın, TOP
çocuk operatörlerinin eşleşen tüm satırları okumadan erken sonlandırmalarına izin vereceği varsayımı olmadan maliyetlendirilmesidir . Bu izleme bayrağı yerinde iken, doğal olarak daha optimal indeks kavşak planı olsun.
SELECT TOP 10 *
FROM animal
WHERE colour LIKE 'black%'
AND species LIKE 'swan'
OPTION (QUERYTRACEON 4138)
Bu plan şu anda her iki endekste 200 bin satırın tamamını okumak için doğru bir maliyettir, ancak aramalar maliyetlerin üzerindedir (tahminen 2 bin ile fiili 0 arasındadır TOP 10
). . Yine de, plan tam CI taramasından çok daha ucuzdur ve bu nedenle seçilir.
Tabii bu plan kombinasyonları için en uygun olmayabilir vardır yaygın. Beyaz kuğular gibi.
Kompozit indeks animal (colour, species)
veya ideal olarak animal (species, colour)
, sorgunun her iki senaryo için de daha verimli olmasına izin verir.
Bileşik endeksi en verimli şekilde kullanmak için LIKE 'swan'
, aynı zamanda değiştirilmesi gerekecektir = 'swan'
.
Aşağıdaki tablo, dört permütasyonun tümü için yürütme planlarında gösterilen arama tahminlerini ve artık tahminleri göstermektedir.
+----------------------------------------------+-------------------+----------------------------------------------------------------+----------------------------------------------+
| WHERE clause | Index | Seek Predicate | Residual Predicate |
+----------------------------------------------+-------------------+----------------------------------------------------------------+----------------------------------------------+
| colour LIKE 'black%' AND species LIKE 'swan' | ix_colour_species | colour >= 'black' AND colour < 'blacL' | colour like 'black%' AND species like 'swan' |
| colour LIKE 'black%' AND species LIKE 'swan' | ix_species_colour | species >= 'swan' AND species <= 'swan' | colour like 'black%' AND species like 'swan' |
| colour LIKE 'black%' AND species = 'swan' | ix_colour_species | (colour,species) >= ('black', 'swan')) AND colour < 'blacL' | colour LIKE 'black%' AND species = 'swan' |
| colour LIKE 'black%' AND species = 'swan' | ix_species_colour | species = 'swan' AND (colour >= 'black' and colour < 'blacL') | colour like 'black%' |
+----------------------------------------------+-------------------+----------------------------------------------------------------+----------------------------------------------+
TOP
Değerin bir değişkende gizlenmesi, bununTOP 100
yerine varsayılacağı anlamına gelirTOP 10
. Bu, iki plan arasındaki devrilme noktasının ne olduğuna bağlı olarak yardımcı olabilir veya olmayabilir.