Joker karakter (veya üstü) eklerken SQL Server sorgusuna büyük yavaşlama


52

SQL Server 2005 veritabanımda takip ettiğim 20 milyon hayvandan oluşan bir hayvanat bahçem var. Bunların yaklaşık% 1'i siyah, yaklaşık% 1'i kuğu. Tüm siyah kuğuların ayrıntılarını almak istedim ve yaptığım sonuç sayfasını değiştirmek istemedim:

select top 10 * 
from animal 
where colour like 'black'  
and species like 'swan'

(Evet, kuşkusuz ki bu alanlar boş. Fakat ikisi de endekslendi). Sorgu yaklaşık 300 milisaniyede boş bir küme döndürdüğü için hiçbir hayvanımız olmadığı ortaya çıktı. Eğer 'beğenmek' yerine '=' kullansaydım iki kat daha hızlı olurdu, ancak ikincisinin bana biraz yazmaktan kurtaracağı bir önsezim var.

Baş hayvan bekçisinin kuğulardan bazılarına 'siyahımsı' olarak girdiğini düşündüğü ortaya çıktı, bu yüzden sorguyu buna göre değiştirdim:

select top 10 * 
from animal  
where colour like 'black%' 
and species like 'swan'

Bunların hiçbirinin olmadığı (ve aslında 'siyah' olanlar dışında 'siyah%' hayvanlarının olmadığı) ancak sorgunun boş kalması yaklaşık 30 saniye sürüyor.

Görünüşe göre sorun sadece 'en üst' ve '%' gibi bir kombinasyona neden oluyor.

select count(*) 
from animal  
where colour like 'black%' 
and species like 'swan'

çok hızlı bir şekilde 0 döndürür ve hatta

select * 
from animal 
where colour like 'black%' 
and species like 'swan'

bir saniyenin kesriyle boşa döner.

Herhangi biri, 'boş' bir sonuç setinde neden bu kadar çarpıcı bir performans kaybına neden olmak için '%' ve '%' nin bir fikir birliğine varması gerektiği konusunda fikriniz var mı?

EDIT: Sadece açıklığa kavuşturmak için, herhangi bir FreeText endeksi kullanmıyorum, sadece alanların giriş noktasında boş, yani veritabanında normalize edilmediğini kastettim. Karışıklık için üzgünüm, benim açımdan kötü sözler.

Yanıtlar:


76

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.

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

Plan, idsü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ı idbu 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). TOP10 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

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

İ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 9130biraz daha bilgi gösterir

SELECT TOP 10 *
FROM   animal
WHERE  colour LIKE 'black%'
       AND species LIKE 'swan'       
OPTION (QUERYTRACEON 9130)  

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

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 TOPdurdurabildiğ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

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

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.

TOPCI 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 10tarama 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)       

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

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%'                         |
+----------------------------------------------+-------------------+----------------------------------------------------------------+----------------------------------------------+

15

Bu merak uyandıran şeyi kurdum, bazı araştırmalar yaptım ve bu Q / A'ya rastladım. TOP bir uygulama planını nasıl (ve neden) etkiler?

Temel olarak, TOP'u kullanmak, takip eden operatörlerin maliyetini (önemsiz bir şekilde) değiştirir; bu, genel planın da değişmesine neden olur (bu, Genel 10'u içeren ve içermeyen ExecPlans'ı dahil ederseniz çok iyi olur); sorgu.

Bu yardımcı olur umarım.

Mesela bir veritabanında denedim ve: -bir top çağrılmadığında, paralellik kullanılmaz-TOP ile paralellik kullanılmaz

Bu nedenle, tekrar yürütme planlarınızı göstermek daha fazla bilgi sağlayacaktır.

İyi günler dilerim


-1

Bunun, MSSQL 2005'in altında yatan doğası ve sorgu iyileştiricisinin hangi yürütme planının en verimli olduğuna karar vermesi nedeniyle olabileceğine inanıyorum.

Bir SQL değişkeni kullanıyorsanız, sorgu optimizerinin iç içe geçmiş döngüler yerine karma eşleşmeleri kullanmaya 'kandırması' gerekir, bu da çok daha yüksek bir paralellik derecesine neden olur.

Deneyin:

DECLARE @topn INT = 10
SELECT TOP (@topn) *
FROM    animal
WHERE   colour LIKE 'black%' 
AND species LIKE 'swan'

5
TOPDeğerin bir değişkende gizlenmesi, bunun TOP 100yerine varsayılacağı anlamına gelir TOP 10. Bu, iki plan arasındaki devrilme noktasının ne olduğuna bağlı olarak yardımcı olabilir veya olmayabilir.
Martin Smith,
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.