PK dizinindeki sütunların sırası önemli midir?


33

Aynı temel yapıya sahip çok büyük birkaç masam var. Her birinin bir RowNumber (bigint)ve DataDate (date)sütunu vardır. Veriler her gece SQLBulkImport kullanılarak yüklenir ve hiçbir "yeni" veri yüklenmez - bu geçmiş bir kayıttır (SQL Standard, Enterprise değil, bölümleme yapmaz).

Çünkü her bir veri bitinin diğer sistemlere geri bağlanması gerekir ve her RowNumber/DataDatekombinasyon benzersizdir, yani Birincil Anahtarım.

PK'yi SSMS Tablo Tasarımcısı'nda tanımlamamdan dolayı RowNumberbirinci ve DataDateikinci sırada olduğunu fark ettim .

Ayrıca, parçalanmamın her zaman ÇOK yüksek olduğunu fark ettim.

Şimdi, her biri DataDateyalnızca bir kez göründüğü için, dizinleyicinin her gün yalnızca sayfalara eklemesini beklerdim, ancak aslında RowNumberilk önce dizin oluşturup oluşturmadığını ve bu nedenle her şeyi kaydırmak zorunda kalacağını merak ediyorum.


Rownumberbir kimlik sütunu değil, dış bir sistem tarafından üretilen bir int (ne yazık ki). Her birinin başında sıfırlanır DataDate.

Örnek veri

RowNumber | DataDate | a | b | c..... 
   1      |2013-08-01| x | y | z 
   2      |2013-08-01| x | y | z 
...
   1      |2013-08-02| x | y | z 
   2      |2013-08-02| x | y | z 
...

Veri, yük başına RowNumberbir adet olmak üzere sırayla DataDateyüklenmektedir.

İçe aktarma işlemi bcp - Bir geçici tabloya yükleme yapmayı denedim ve daha sonra oradan sırayla seçtim ( ORDER BY RowNumber, DataDate) ancak yine de yüksek parçalanma ortaya çıkıyor.

Yanıtlar:


50

PK dizinindeki sütunların sırası önemli midir?

Evet öyle.

Varsayılan olarak, birincil anahtar kısıtlaması, benzersiz bir kümelenmiş dizin tarafından SQL Server'da uygulanır. Kümelenmiş dizin , tablodaki satırların mantıksal sırasını tanımlar . B-ağacı endeksinin üst seviyelerini temsil etmek için eklenmiş bir kaç ilave indeks sayfası olabilir, fakat kümelenmiş bir indeksin en düşük (yaprak) seviyesi sadece verinin mantıksal sırasıdır.

Açıkçası, bir sayfadaki satırların fiziksel olarak kümelenmiş dizin anahtarı sırasına göre depolanması gerekmez . Sayfa içinde her satıra bir işaretçi koyan ayrı bir yönlendirme yapısı vardır. Bu yapı, kümelenmiş dizin tuşları ile sıralanır. Ayrıca, her sayfa kümelenmiş dizin tuşu sırasındaki aynı düzeyde önceki ve sonraki sayfaya bir işaretçi içerir.

Kümelenmiş bir birincil anahtar ile (RowNumber, DataDate), satırlar önce mantıksal olarak önce RowNumberve sonra DataDatesırayla - yani RowNumber = 1mantıksal olarak gruplandırılmış tüm satırlar , sonra nerede RowNumber = 2ve benzerleri tarafından sıralanır .

Yeni veriler eklediğinizde ( RowNumbers1'den n'ye kadar olan) yeni satırlar mantıksal olarak varolan sayfalara aittir, bu nedenle SQL Server'ın yer açmak için büyük miktarda iş bölme sayfası yapması gerekir. Tüm bu faaliyetler kazanç elde etmek için (değişikliklerin kaydedilmesi dahil) çok fazla ek iş üretiyor.

Bölünmüş sayfalar da yaklaşık% 50 boşalmaya başlar, bu nedenle aşırı bölme düşük sayfa yoğunluğuna (sayfa başına en uygun olandan daha az satır) neden olabilir. Diskten okumak için sadece bu kötü haber değil (düşük yoğunluklu = okunacak daha fazla sayfa), düşük yoğunluklu sayfalar da önbellekte saklandıklarında bellekte daha fazla yer kaplar.

Kümelenmiş dizininin olarak değiştirilmesi, (DataDate, RowNumberyeni DataDatessayfaların (muhtemelen şu anda depolanandan daha yüksek olan) yeni sayfalarda kümelenmiş dizinin mantıksal sonuna eklendiği anlamına gelir . Bu, sayfaların gereksiz yere aşırı yüklenmesini ortadan kaldıracak ve daha hızlı yükleme süresi sağlayacaktır. Daha az parçalı veri aynı zamanda ileriye dönük bir etkinliğin (devam eden bir sorgu için hemen önce diskten sayfaları okumak) daha verimli olabileceği anlamına gelir.

Başka bir şey, sorgularınız arama yapmak için çok daha muhtemeldir DataDatedaha RowNumber. Kümelenmiş bir dizin açık (DataDate, RowNumber), dizinin aranmasını DataDate(ve sonra RowNumber) destekler. Mevcut düzenleme, yalnızca üzerinde araştırma yapmayı destekler RowNumber(ve ancak o zaman, belki de DataDate). DataDateBirincil anahtar değiştirildikten sonra mevcut kümelenmemiş dizini bırakabilirsiniz . Kümelenmiş dizin, değiştirildiği kümelenmemiş dizinden daha geniş olacaktır, bu nedenle performansın kabul edilebilir kaldığından emin olmak için test etmelisiniz.

Yeni verileri içe aktarırken bcp, içe aktarma dosyasındaki veriler kümelenmiş dizin tuşlarına göre (ideal olarak (DataDate, RowNumber) sıralanırsa ve bcpseçeneği belirtirseniz daha yüksek performans elde edebilirsiniz :

-h "ORDER(DataDate,RowNumber), TABLOCK"

En iyi veri yükleme performansı için, minimum düzeyde giriş yapmış ekler elde etmeye çalışabilirsiniz. Daha fazla bilgi için bakınız:


4
Mükemmel bir cevap - şimdi ne yapmam gerektiğini ve nedenini biliyorum. Ben de öyle düşünmüştüm, ama öyle değil! Teşekkür ederim.
BlueChippy

DB'yi test etmek için yerel SQL Server'ım içine alırken bir LOOOOONG aldı: Dizin yükünü değiştirmeden önce 45 dakika sürdü ... sonra, sadece 5 !!!
BlueChippy

13

Evet, sipariş kritik. RowNumber (örn. WHERE RowNumber=1) Tarafından sorgulandığınızdan kesinlikle şüpheliyim . Büyük ölçüde zaman serileri tarihe ( WHERE DataDate BEWEEN @start AND @end) göre sorgulanır ve bu tür sorgular kümelenmiş bir kuruluş tarafından gerektirir DataDate.

Parçalanma genel olarak kırmızı bir ringa balığıdır. Parçalanmayı azaltmak, buradaki hedefiniz olmamalı, ancak sorularınız için uygun bir organizasyona sahip olmalıdır. Buna ek olarak, parçalanmanın azalmasının sağlanması iyi bir fikir olduğunu düşünür, ancak kendi başına bir amaç değildir. İş yükünüze uygun düzgün bir şekilde düzenlenmiş bir veri modeliniz varsa (sorgularınız doğru şekilde ele alındığında ) ve parçalanmanın performansı etkilediğini gösteren ölçümleriniz varsa, bunun hakkında konuşabiliriz.


Ayrıca DataDate üzerinde kümelenmemiş bir indeks (ler) var, bu sizin söylediğiniz gibi çoğu zaman WHEREsorgularda yan tümcedir .
BlueChippy

1
Sütunların SİPARİŞİ kritikse, yanlış siparişin etkisi G / Ç artışımı görür mü? Benim düşüncem, RowNumber'a göre sıralanması ve bu yüzden her seferinde indeksler üzerinde çok fazla çalışma yapması gerektiği, buna karşın DataDate'e dayanması gerektiğidir?
BlueChippy
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.