Optimizer neden Kümelenmemiş Dizin yerine Kümelenmiş Dizin + Sırala'yı seçsin?


11

Bir sonraki örnekte:

IF OBJECT_ID('dbo.my_table') IS NOT NULL
    DROP TABLE [dbo].[my_table];
GO

CREATE TABLE [dbo].[my_table]
(
    [id]    int IDENTITY (1,1)  NOT NULL PRIMARY KEY,
    [foo]   int                 NULL,
    [bar]   int                 NULL,
    [nki]   int                 NOT NULL
);
GO

/* Insert some random data */
INSERT INTO [dbo].[my_table] (foo, bar, nki)
SELECT TOP (100000)
    ABS(CHECKSUM(NewId())) % 14,
    ABS(CHECKSUM(NewId())) % 20,
    n = CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id]))
FROM 
    sys.all_objects AS s1 
CROSS JOIN 
    sys.all_objects AS s2
GO

CREATE UNIQUE NONCLUSTERED INDEX [IX_my_table]
    ON [dbo].[my_table] ([nki] ASC);
GO

[nki](Kümelenmemiş dizin) tarafından sıralanan tüm kayıtları getirirsem :

SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table ORDER BY nki;
SET STATISTICS TIME OFF;

SQL Server Execution Times: CPU time = 266 ms, elapsed time = 493 ms

Optimize Edici, kümelenmiş dizini seçer ve ardından bir Sıralama algoritması uygular.

resim açıklamasını buraya girin

Execution plan

Ancak kümelenmemiş dizini kullanmaya zorlarsam:

SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table WITH(INDEX(IX_my_TABLE));
SET STATISTICS TIME OFF;

SQL Server Execution Times: CPU time = 311 ms, elapsed time = 188 ms

Daha sonra Anahtar Arama ile kümelenmemiş dizin kullanır:

resim açıklamasını buraya girin

Execution plan

Açıkçası, kümelenmemiş dizin bir kaplama dizinine dönüştürülürse:

CREATE UNIQUE NONCLUSTERED INDEX [IX_my_table]
    ON [dbo].[my_table] ([nki] ASC)
    INCLUDE (id, foo, bar);
GO

Sonra sadece bu dizini kullanır:

SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table ORDER BY nki;
SET STATISTICS TIME OFF;

SQL Server Execution Times: CPU time = 32 ms, elapsed time = 106 ms

resim açıklamasını buraya girin

Execution plan


Soru

  • SQL Server, yürütme süresi ikinci durumda% 38 daha hızlı olsa bile neden kümelenmiş dizin artı bir kümelenmiş dizin kullanmak yerine bir sıralama algoritması kullanıyor?

1
Zorunlu dizin sorgunuzda ORDER BY'ı bırakmak mı demek istediniz?
Forrest

Yanıtlar:


9

SQL Server, yürütme süresi ikinci durumda% 38 daha hızlı olsa bile neden kümelenmiş dizin artı bir kümelenmiş dizin kullanmak yerine bir sıralama algoritması kullanıyor?

SQL Server, çalışma zamanı bilgilerini değil, istatistiklere dayalı maliyet tabanlı bir iyileştirici kullandığından.

Bu sorgu için maliyet tahmin işlemi sırasında, aslında arama planını değerlendirir, ancak daha fazla çaba harcayacağını tahmin eder. (Yürütme planında SELECT üzerine gelindiğinde "Tahmini Alt Ağaç Maliyeti" ne dikkat edin). Bu mutlaka kötü bir varsayım değildir - test makinemde, arama planı sıralama / taramanın CPU'sunu 6X alır.

Rob Farley'in SQL Server'ın arama planına neden daha yüksek maliyetli olabileceğine ilişkin cevabına bakın.


9

100.000 aramada gereken okuma sayısını bir sıralamada yer alanlarla karşılaştırırsanız, Query Optimizer'ın neden CIX + Sort'un en iyi seçim olacağını düşündüğü hakkında hızlıca bir fikir edinebilirsiniz.

Arama yürütme işlemi daha hızlı olur çünkü okunan sayfalar bellekte olur (önbelleği temizleseniz bile, sayfa başına çok sayıda satırınız vardır, bu nedenle aynı sayfaları tekrar tekrar okuyorsunuz, ancak farklı miktarlarda parçalanma ile veya diğer etkinliklerden farklı bellek basıncı, durum böyle olmayabilir). CIX + Sort'un daha hızlı gitmesi gerçekten çok fazla şey gerektirmez, ancak gördüğünüz şey, bir okuma maliyetinin aynı sayfalara tekrar tekrar vurmanın göreli ucuzluğunu dikkate almamasıdır.


4

Bu soruya biraz kazmaya karar verdim ve nasıl ve ne zaman kullanıldığını veya daha iyi olduğunu, kümelenmemiş bir dizinin kullanımını zorlamayacağından bahsettiğim bazı ilginç belgeler buldum.

John Eisbrener'in yorumlarına göre , en çok referans alanlardan biri, hatta diğer bloglarda bile, Kimberly L. Tripp'in bu ilginç makalesi:

ancak sadece bu değil, eğer ilgileniyorsanız bu sayfalara göz atabilirsiniz:

Gördüğünüz gibi, hepsi Devrilme noktası kavramı etrafında hareket ediyor .

Alıntı sahibi KL Tripp yazı

Devrilme noktası nedir?

Döndürülen satır sayısının " artık yeterince seçici olmadığı " noktadır . SQL Server karşılık gelen veri satırlarını aramak için kümelenmemiş dizini KULLANMAYI seçer ve bunun yerine bir tablo taraması gerçekleştirir.

SQL Server, bir yığın üzerinde kümelenmemiş bir dizin kullandığında, temel olarak temel tablonun sayfalarına bir işaretçi listesi alır. Ardından, Satır Kimliği Aramaları (RID) adı verilen bir dizi işlemle satırları almak için bu işaretçileri kullanır. Bu, en azından, döndürülen satır sayısı kadar ve belki de daha fazla sayfa okuması kullanacağı anlamına gelir. İşlem, temel tablo olarak kümelenmiş bir dizine biraz benzer, aynı sonuçla: daha fazla okuma.

Ancak, bu devrilme noktası meydana geldiğinde?

Elbette bu hayattaki çoğu şey gibi, o da ...

Cidden değil, sayfa başına kaç satıra bağlı olarak tablodaki sayfa sayısının% 25 ila% 33'ü arasında gerçekleşir. Ancak dikkate almanız gereken daha fazla faktör var:

ITPRoToday makalesinden alıntı

Devrilme Noktasını Etkileyen Diğer Faktörler RID aramalarının maliyeti devrilme noktasını etkileyen en önemli faktör olmasına rağmen, bir dizi başka faktör vardır:

  • Kümelenmiş bir dizini tararken fiziksel G / Ç çok daha verimlidir. Kümelenmiş dizin verileri, dizine sırasıyla dizin sırasına göre yerleştirilir. Sonuç olarak, disk üzerinde G / Ç performansını artıran çok az yan kafa hareketi vardır.
  • Veritabanı motoru kümelenmiş bir dizini tararken, disk izindeki sonraki birkaç sayfanın hala ihtiyaç duyduğu verileri içerme olasılığının yüksek olduğunu bilir. Bu nedenle, normal 8KB sayfalar yerine 64KB boyutunda okumaya başlar. Bu aynı zamanda daha hızlı G / Ç ile sonuçlanır.

Şimdi istatistiklerimi IO kullanarak sorgularımı tekrar çalıştırırsam:

SET STATISTICS IO ON;
SELECT id, foo, bar, nki FROM my_table WHERE nki < 20000 ORDER BY nki ;
SET STATISTICS IO OFF;

Logical reads: 312

SET STATISTICS IO ON;
SELECT id, foo, bar, nki FROM my_table WITH(INDEX(IX_my_TABLE));
SET STATISTICS IO OFF;

Logical reads: 41293

İkinci sorgu, birincisinden daha mantıklı okumalara ihtiyaç duyar.

Kümelenmemiş dizinden kaçınmalı mıyım?

Hayır, kümelenmiş bir dizin yararlı olabilir, ancak zaman ayırmaya ve onunla elde etmeye çalıştığınız şeyi analiz etmek için ekstra çaba sarf etmeye değer.

Alıntı sahibi KL Tripp yazı

Peki ne yapmalısın? Değişir. Verilerinizi iyi tanıyorsanız ve bir ipucu kullanmayı düşünebileceğiniz bazı kapsamlı testler yapıyorsanız (sps'de programlı olarak yapabileceğiniz bazı akıllı şeyler var, yakında bir gönderi yapmaya çalışacağım). Ancak, (eğer mümkünse) çok daha iyi bir seçim, kaplamayı düşünmektir (bu gerçekten benim asıl amacım :). Sorgularımda kaplama gerçekçi değil çünkü sorgularım tüm sütunları istiyor (kötü SELECT *), ancak sorgularınız daha darsa ve yüksek önceliğe sahipse, bir ipucu üzerinden bir kaplama diziniyle (birçok durumda) daha iyi durumdasınız çünkü bir sorguyu kapsayan bir dizin, asla ipuçları.

Şimdilik bulmacanın cevabı bu ama kesinlikle dalmak için çok daha fazlası var. Devrilme Noktası çok iyi bir şey olabilir - ve genellikle iyi çalışır. Ancak, bir dizini zorlayabileceğinizi ve daha iyi performans elde edebileceğinizi düşünüyorsanız, biraz araştırma yapmak ve bunun olup olmadığını görmek isteyebilirsiniz. Sonra bir ipucunun ne kadar yardımcı olabileceğini düşünün ve şimdi nereye odaklanabileceğinizi biliyorsunuz.

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.