Kümelenmemiş Dizinlerin Kümelenmiş Dizinlere Karşı Yığınlardaki Performansı


39

Bu 2007 Beyaz Kitap , kümelenmiş bir dizin olarak düzenlenmiş bir tablodaki tek tek seçme / ekleme / silme / güncelleme ve aralık seçme ifadelerinin performansını karşılaştırır; buna karşılık, CI ile aynı anahtar sütunlarda kümelenmemiş bir dizine sahip bir yığın olarak düzenlenmiş bir tabloda tablo.

Genel olarak, kümelenmiş indeks seçeneği testlerde daha iyi sonuç vermiştir; çünkü bakımı yapılacak tek bir yapı vardır ve yer imi aramalarına gerek yoktur.

Makale kapsamına girmeyen potansiyel olarak ilginç bir durum, bir kümedeki kümelenmemiş indeks ile kümelenmiş bir endeks üzerindeki kümelenmemiş bir indeks arasındaki karşılaştırma olabilir. Bu durumda, yığının NCI yaprak seviyesinde bir kez daha iyi performans göstereceğini umuyordum, SQL Server kümelenmiş dizini geçmek zorunda kalmak yerine doğrudan takip etmesi gereken bir RID'ye sahipti.

Bu alanda gerçekleştirilen benzer resmi testlerden haberdar olan var mı ve eğer öyleyse sonuçlar ne oldu?

Yanıtlar:


41

İsteğinizi kontrol etmek için bu şemayı takip ederek 2 tablo oluşturdum:

  • Bakiye bilgilerini gösteren 7.9 milyon kayıt.
  • 1 ile 7,9 milyon arasında değişen bir kimlik alanı
  • 500k grubundaki kayıtları gruplayan bir sayı alanı.

Çağrılan ilk tablo heap, alanda kümelenmemiş bir dizin aldı group. İkinci tablo çağrılan clustsıralı alanda keykümelenmiş bir dizini ve bu alanda kümelenmemiş bir dizini aldıgroup

Testler, 2 yüksek geçirgen çekirdekli çekirdek, 4 Gb bellek ve 64 bit windows 7 olan bir I5 M540 işlemcide gerçekleştirildi.

Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (X64) 
Apr  2 2010 15:48:46 
Developer Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)  

9 Mar 2011 tarihli güncelleme : Aşağıdaki .net kodunu çalıştırarak ve Sql Server Profiler'da Süre, İşlemci, Okur, Yazma ve Satır Sayılarını günlüğe kaydederek ikinci daha kapsamlı bir kıyaslama yaptım. (Kullanılan CommandText sonuçlarında bahsedilecektir.)

NOT: CPU ve Süre milisaniye cinsinden ifade edilir

  • 1000 sorgu
  • sıfır CPU sorgusu sonuçlardan elimine edildi
  • Etkilenen 0 satır sonuçlardan elimine edildi
int[] idList = new int[] { 6816588, 7086702, 6498815 ... }; // 1000 values here.
using (var conn = new SqlConnection(@"Data Source=myserver;Initial Catalog=mydb;Integrated Security=SSPI;"))
            {
                conn.Open();
                using (var cmd = new SqlCommand())
                {
                    cmd.Connection = conn;
                    cmd.CommandType = CommandType.Text;
                    cmd.CommandText = "select * from heap where common_key between @id and @id+1000"; 
                    cmd.Parameters.Add("@id", SqlDbType.Int);
                    cmd.Prepare();
                    foreach (int id in idList)
                    {
                        cmd.Parameters[0].Value = id;

                        using (var reader = cmd.ExecuteReader())
                        {
                            int count = 0;
                            while (reader.Read())
                            {
                                count++;
                            }
                            Console.WriteLine(String.Format("key: {0} => {1} rows", id, count));
                        }
                    }
                }
            }

9 Mar 2011 tarihli güncelleme sonu .

SELECT performansı

Performans numaralarını kontrol etmek için, aşağıdaki sorguları yığın tablosunda bir kez ve küme tablosunda bir kez gerçekleştirdim:

select * from heap/clust where group between 5678910 and 5679410
select * from heap/clust where group between 6234567 and 6234967
select * from heap/clust where group between 6455429 and 6455729
select * from heap/clust where group between 6655429 and 6655729
select * from heap/clust where group between 6955429 and 6955729
select * from heap/clust where group between 7195542 and 7155729

Bu kıyaslamanın sonuçları şunlar içindir heap:

rows  reads CPU   Elapsed 
----- ----- ----- --------
1503  1510  31ms  309ms
401   405   15ms  283ms
2700  2709  0ms   472ms
0     3     0ms   30ms
2953  2962  32ms  257ms
0     0     0ms   0ms

9 Mar 2011 tarihli güncelleme : cmd.CommandText = "select * from heap where group between @id and @id+1000";

  • 721 Satırlar> 0 CPU'ya sahiptir ve 0 satırdan fazlasını etkiler
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1001      69788    6368         -         
Cpu            15        374      37   0.00754
Reads        1069      91459    7682   1.20155
Writes          0          0       0   0.00000
Duration   0.3716   282.4850 10.3672   0.00180

9 Mar 2011 tarihli güncelleme sonu .


Tablo clustiçin sonuçlar:

rows  reads CPU   Elapsed 
----- ----- ----- --------
1503  4827  31ms  327ms
401   1241  0ms   242ms
2700  8372  0ms   410ms
0     3     0ms   0ms
2953  9060  47ms  213ms
0     0     0ms   0ms

9 Mar 2011 tarihli güncelleme : cmd.CommandText = "select * from clust where group between @id and @id+1000";

  • 721 Satırlar> 0 CPU'ya sahiptir ve 0 satırdan fazlasını etkiler
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1001      69788    6056         -
Cpu            15        468      38   0.00782
Reads        3194     227018   20457   3.37618
Writes          0          0       0       0.0
Duration   0.3949   159.6223 11.5699   0.00214

9 Mar 2011 tarihli güncelleme sonu .


BİRLEŞTİRME performansına sahip SELECT

cmd.CommandText = "select * from heap/clust h join keys k on h.group = k.group where h.group between @id and @id+1000";


Bu kıyaslamanın sonuçları şunlar içindir heap:

873 Satır> 0 CPU var ve 0 satırdan fazla etkiliyor

Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1009       4170    1683         -
Cpu            15         47      18   0.01175
Reads        2145       5518    2867   1.79246
Writes          0          0       0   0.00000
Duration   0.8215   131.9583  1.9095   0.00123

Bu kıyaslamanın sonuçları şunlar içindir clust:

865 Satırlar> 0 CPU'ya sahiptir ve 0 satırdan fazlasını etkiler

Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1000       4143    1685         -
Cpu            15         47      18   0.01193
Reads        5320      18690    8237   4.97813
Writes          0          0       0   0.00000
Duration   0.9699    20.3217  1.7934   0.00109

GÜNCELLEME performans

İkinci sorgu grubu güncelleme ifadeleridir:

update heap/clust set amount = amount + 0 where group between 5678910 and 5679410
update heap/clust set amount = amount + 0 where group between 6234567 and 6234967
update heap/clust set amount = amount + 0 where group between 6455429 and 6455729
update heap/clust set amount = amount + 0 where group between 6655429 and 6655729
update heap/clust set amount = amount + 0 where group between 6955429 and 6955729
update heap/clust set amount = amount + 0 where group between 7195542 and 7155729

Bu kriterin sonuçları heap:

rows  reads CPU   Elapsed 
----- ----- ----- -------- 
1503  3013  31ms  175ms
401   806   0ms   22ms
2700  5409  47ms  100ms
0     3     0ms   0ms
2953  5915  31ms  88ms
0     0     0ms   0ms

9 Mar 2011 tarihli güncelleme : cmd.CommandText = "update heap set amount = amount + @id where group between @id and @id+1000";

  • 811 Satırlar> 0 CPU'ya sahiptir ve 0 satırdan fazlasını etkiler
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1001      69788    5598       811         
Cpu            15        873      56   0.01199
Reads        2080     167593   11809   2.11217
Writes          0       1687     121   0.02170
Duration   0.6705   514.5347 17.2041   0.00344

9 Mar 2011 tarihli güncelleme sonu .


Bu kriterin sonuçları clust:

rows  reads CPU   Elapsed 
----- ----- ----- -------- 
1503  9126  16ms  35ms
401   2444  0ms   4ms
2700  16385 31ms  54ms
0     3     0ms   0ms 
2953  17919 31ms  35ms
0     0     0ms   0ms

9 Mar 2011 tarihli güncelleme : cmd.CommandText = "update clust set amount = amount + @id where group between @id and @id+1000";

  • 853 Satırlar> 0 CPU'ya sahiptir ve 0 satırdan fazlasını etkiler
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1001      69788    5420         -
Cpu            15        594      50   0.01073
Reads        6226     432237   33597   6.20450
Writes          0       1730     110   0.01971
Duration   0.9134   193.7685  8.2919   0.00155

9 Mar 2011 tarihli güncelleme sonu .


DELETE benchmarkları

koştuğum üçüncü sorgu grubu ifadeleri sil

delete heap/clust where group between 5678910 and 5679410
delete heap/clust where group between 6234567 and 6234967
delete heap/clust where group between 6455429 and 6455729
delete heap/clust where group between 6655429 and 6655729
delete heap/clust where group between 6955429 and 6955729
delete heap/clust where group between 7195542 and 7155729

Bu kriterin sonucu heap:

rows  reads CPU   Elapsed 
----- ----- ----- -------- 
1503  10630 62ms  179ms
401   2838  0ms   26ms
2700  19077 47ms  87ms
0     4     0ms   0ms
2953  20865 62ms  196ms
0     4     0ms   9ms

9 Mar 2011 tarihli güncelleme : cmd.CommandText = "delete heap where group between @id and @id+1000";

  • 724 Satırlar> 0 CPU'ya sahiptir ve 0 satırdan fazlasını etkiler
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts     192      69788    4781         -
Cpu            15        499      45   0.01247
Reads         841     307958   20987   4.37880
Writes          2       1819     127   0.02648
Duration   0.3775  1534.3383 17.2412   0.00349

9 Mar 2011 tarihli güncelleme sonu .


Bu kriterin sonucu clust:

rows  reads CPU   Elapsed 
----- ----- ----- -------- 
1503  9228  16ms  55ms
401   3681  0ms   50ms
2700  24644 46ms  79ms
0     3     0ms   0ms
2953  26955 47ms  92ms
0     3     0ms   0ms

9 Mar 2011 tarihli güncelleme :

cmd.CommandText = "delete clust where group between @id and @id+1000";

  • 751 Satırlar> 0 CPU'ya sahiptir ve 0 satırdan fazlasını etkiler
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts     144      69788    4648         -
Cpu            15        764      56   0.01538
Reads         989     458467   30207   6.48490
Writes          2       1830     127   0.02694
Duration   0.2938  2512.1968 24.3714   0.00555

9 Mar 2011 tarihli güncelleme sonu .


INSERT kriterleri

Benchmarkın son kısmı insert ifadelerinin uygulanmasıdır.

yığın / küme (...) değerlerine (...), (...), (...), (...), (...), (...)


Bu kriterin sonucu heap:

rows  reads CPU   Elapsed 
----- ----- ----- -------- 
6     38    0ms   31ms

9 Mar 2011 tarihli güncelleme :

string str = @"insert into heap (group, currency, year, period, domain_id, mtdAmount, mtdAmount, ytdAmount, amount, ytd_restated, restated, auditDate, auditUser)
                    values";

                    for (int x = 0; x < 999; x++)
                    {
                        str += string.Format(@"(@id + {0}, 'EUR', 2012, 2, 0, 100, 100, 1000 + @id,1000, 1000,1000, current_timestamp, 'test'),  ", x);
                    }
                    str += string.Format(@"(@id, 'CAD', 2012, 2, 0, 100, 100, 1000 + @id,1000, 1000,1000, current_timestamp, 'test') ", 1000);

                    cmd.CommandText = str;
  • 912 ifadelerinde> 0 CPU var
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1000       1000    1000         -
Cpu            15       2138      25   0.02500
Reads        5212       7069    6328   6.32837
Writes         16         34      22   0.02222
Duration   1.6336   293.2132  4.4009   0.00440

9 Mar 2011 tarihli güncelleme sonu .


Bu kriterin sonucu clust:

rows  reads CPU   Elapsed 
----- ----- ----- -------- 
6     50    0ms   18ms

9 Mar 2011 tarihli güncelleme :

string str = @"insert into clust (group, currency, year, period, domain_id, mtdAmount, mtdAmount, ytdAmount, amount, ytd_restated, restated, auditDate, auditUser)
                    values";

                    for (int x = 0; x < 999; x++)
                    {
                        str += string.Format(@"(@id + {0}, 'EUR', 2012, 2, 0, 100, 100, 1000 + @id,1000, 1000,1000, current_timestamp, 'test'),  ", x);
                    }
                    str += string.Format(@"(@id, 'CAD', 2012, 2, 0, 100, 100, 1000 + @id,1000, 1000,1000, current_timestamp, 'test') ", 1000);

                    cmd.CommandText = str;
  • 946 ifadede> 0 CPU var
Counter   Minimum    Maximum Average  Weighted
--------- ------- ---------- ------- ---------
RowCounts    1000       1000    1000         -      
Cpu            15       2403      21   0.02157
Reads        6810       8997    8412   8.41223
Writes         16         25      19   0.01942
Duration   1.5375   268.2571  6.1463   0.00614

9 Mar 2011 tarihli güncelleme sonu .


Sonuçlar

Tabloya kümelenmiş ve kümelenmemiş dizinle (kümelenmemiş dizini kullanırken) erişirken daha mantıklı okumalar olmasına rağmen performans sonuçları şöyledir:

  • SELECT ifadeleri karşılaştırılabilir
  • UPDATE ifadeleri, kümelenmiş bir dizin olduğunda daha hızlı
  • DELETE ifadeleri, kümelenmiş bir dizin olduğunda daha hızlı
  • INSERT ifadeleri, kümelenmiş bir dizin olduğunda daha hızlı

Tabi ki kıyaslamam belirli bir masa türünde ve çok sınırlı bir sorgu setinde çok sınırlıydı, ancak bu bilgilere dayanarak tablonuzda kümelenmiş bir indeks oluşturmanın neredeyse her zaman daha iyi olduğunu söylemeye başlayabileceğimizi düşünüyorum.

9 Mar 2011 tarihli güncelleme :

Eklenen sonuçlardan da anlaşılacağı gibi, sınırlı testler hakkındaki sonuçlar her durumda doğru değildi.

Ağırlıklı Süre

Sonuçlar, kümelenmiş endeksten yararlanan tek ifadelerin güncelleme ifadeleri olduğunu göstermektedir. Diğer ifadeler, kümelenmiş indeksli tabloda yaklaşık% 30 daha yavaş.

Yığa vs clust için sorgu başına ağırlıklı süre grafiğini çizdiğim bazı ek grafikler. Seçme için kümelenmiş ağırlıklı Süre yığını

Ağırlıklı Süre yığını, Katılma için kümelenmiş vs

Güncelleme için kümelenmiş ağırlıklı Süre yığını

Silme için kümelenmiş ağırlıklı Süre yığını

İnsert ifadelerinin performans profilini görebileceğiniz gibi oldukça ilginç. Çiviler, tamamlanması daha uzun süren birkaç veri noktasından kaynaklanır. Insert için kümelenmiş ağırlıklı Süre yığını

9 Mar 2011 tarihli güncelleme sonu .


@Martin Gelecek hafta biraz zaman bulduğumda 500 milyon kaydı olan birkaç masadan oluşan bir sunucuda çalıştırmaya çalışacağım.
Filip De Vos,

Bu testin doğruluğundan şüpheliyim. Kümelenmiş endeksin daha hızlı olduğunu iddia eden INSERT performansı gibi bazı parçaların ciddi dikkat göstermesi gerekiyor - CLUST sürümünde daha fazla okuma vardı, ancak geçen süre daha az. Şahsen geçen sürenin 10 milisaniyelik (zamanlama değişkenliği) içinde olduğunu görmezden gelirdim - bu okuma sayımından daha az anlamına gelir.

Kimberly Tripp'in Kümelenmiş Endeksi Tartışması , kümelenmiş bir masaya sahip çoğu (hepsi olmasa da) işlemlerin neden bir yığından daha hızlı olduğunu açıklar - sonuçlarınızın aksine ...
marc_s

1
@ Martin, @Richard, @marc_s. Şu an daha ciddi bir kriter üzerinde çalışıyorum. Sonuçları daha sonra bugün ekleyebilmeyi umuyorum.
Filip De Vos

1
@Filip - Vay canına! Bu cevaba verdiğiniz zor işin karşılığını kesinlikle hak ediyorsunuz. Her ne kadar haklı olarak işaret etmiş olsanız da, bu çok sınırlı bir dizi sorguyla belirli bir masa türünde bir ölçüt oldu ve kilometre şüphesiz değişecektir.
Martin Smith

12

Dizin Oluşturma Kraliçesi Kimberly Tripp'in blog yazısında gayet güzel bir şekilde açıkladığı gibi, Kümelenmiş Dizin Tartışması devam ediyor ... bir veritabanı tablosundaki kümelenme anahtarına sahip olmak, tüm işlemleri büyük ölçüde hızlandırıyor - sadece SELECT.

SELECT genellikle bir yığın üzerinde kümelenmiş bir tabloya göre daha yavaştır, iyi bir kümeleme anahtarı seçtiğiniz sürece - a INT IDENTITY. Bir GUID veya değişken uzunluktaki birçok bileşene sahip bir bileşik anahtar gibi gerçekten kötü bir kümeleme anahtarı kullanırsanız, ancak yalnızca o zaman bir yığın daha hızlı olabilir. Ancak bu durumda, ilk başta veritabanı tasarımınızı temizlemeniz gerekir ...

Genel olarak, bir yığında herhangi bir nokta olduğunu düşünmüyorum - iyi, kullanışlı bir kümeleme anahtarı seçin ve her bakımdan faydalanmalısınız.


3
Bu bir cevap değil. Martin, SQL Server'da oldukça sağlam; Bu soru, gerçek dünyadan, test teorisinden değil, performans testinden elde edilen doğrulanmış sonuçları elde etmek için yapıldı.

Kimberly Tripp'in makalesi etkin bir şekilde kümelenmemiş indekslerin tümünü kapsadığını varsaymaktadır. Eğer durum buysa, hiçbir arama olmaz ve yığının aramalardaki avantajı göz ardı edilir. Bu, çoğumuz içinde yaşadığımız bir dünya değil. Bizim durumlarımızda, kümelenmemiş dizinlerimizin tümünü veya çoğunu kapsayacak şekilde tasarlamaya çalışmak kendi başına sorun yaratır.

@ dbaguy52: neden sizce Kim Tripp NC indekslerinin tümünü koruduğunu varsayıyor? Onun blog yazısında bunun hiçbir fikrini görmüyorum ..... lütfen durumun (ya da varsayımının bu olduğuna inandığına) neyin sebep olduğunu daha ayrıntılı olarak açıklayın
marc_s

7

Bu soruyu ele alan Joe Chang'in bu makalesine rastladım . Sonuçlarını aşağıya yapıştırdım.

Dizinlerin derinliği 4 olan bir tablo düşünün, böylelikle bir kök seviyesi, 2 orta seviye ve yaprak seviyesi olacaktır. Dizin tek bir dizin anahtarı arar (yani, hiçbir anahtar araması yapılmaz) 4 mantıksal IO (LIO) oluşturur. Şimdi bir anahtar araması gerekli olup olmadığını düşünün. Eğer tablonun derinliği 4 aynı zamanda kümelenmiş bir indeks ise, her anahtar araması 4 LIO oluşturur. Tablo bir yığınsa, her bir anahtar araması 1 LIO oluşturur. Gerçekte, bir yığına yapılan anahtar araması, 4: 1 LIO oranına yakın hiçbir yerde değil, kümelenmiş bir dizine yapılan anahtar araştırmasından% 20-30 daha ucuzdur.


1
Unutulmaması gereken ilginç şey, Joe Chang’den yapılan teklifin 9 Mart’taki güncellemede belirtilen avantajla hemen hemen aynı avantajı olan varsayımlarına dayanarak yığınlar için% 20-30’lık bir verimlilik avantajı belirlemesidir.
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.