Bir birincil anahtar ne zaman kümelenmemiş olarak bildirilmelidir?


169

Daha önce sorduğum başka bir soru için bir test veritabanı oluştururken, bildirilebilecek bir Birincil Anahtar hakkında hatırladım. NONCLUSTERED

Bir NONCLUSTEREDbirincil anahtar yerine, bir CLUSTEREDbirincil anahtarı ne zaman kullanırsınız ?

Şimdiden teşekkürler

Yanıtlar:


187

'PK ne zaman NC olmalıdır' sorusu değil, bunun yerine 'kümelenmiş dizin için uygun anahtarın ne olduğunu' sormalısınız.

Ve cevap gerçekten verileri nasıl sorguladığınıza bağlı . Kümelenmiş indeks, diğer tüm indekslere göre bir avantaja sahiptir: her zaman tüm sütunları içerdiğinden, her zaman kapsar. Bu nedenle, kümelenmiş dizini kaldırabilecek sorguların, yansıtılan sütunların ve / veya tahminlerin bir kısmını karşılamak için kesinlikle arama kullanmasına gerek yoktur.

Bulmacanın bir başka parçası da bir endeksin nasıl kullanılabileceği ? Üç tipik kalıp vardır:

  • Sonda, endekste tek bir anahtar değer arandığında
  • aralık, bir anahtar değer aralığı alındığında tarar
  • Bir endeks, dur-kalk sıralama gerektirmeksizin bir siparişi karşılayabildiğinde gereksinimlere göre sırala

Öyleyse, beklenen yükünüzü (sorgular) analiz ederseniz ve çok sayıda sorgunun belirli bir dizini kullanacağını keşfederseniz, bir dizinden yararlanan belirli bir erişim kalıbı kullanırlarsa, o dizini kümelenmiş dizin olarak önermek mantıklı olur.

Diğer bir faktör, kümelenmiş indeks anahtarının kümelenmemiş tüm indekslerin kullandığı arama anahtarı olmasıdır ve bu nedenle geniş bir kümelenmiş indeks anahtarının bir dalgalanma efekti yaratması ve kümelenmemiş tüm indekslerin genişlemesi ve geniş endekslerin daha fazla sayfa, daha fazla I / O olması , daha fazla hafıza, daha az iyilik.

İyi bir kümelenmiş indeks sabittir , kümelenmiş indeks anahtar değerlerinde bir değişiklik olması durumunda satırın silinmesi ve geri eklenmesi gerektiği anlamına gelir.

Ve iyi bir kümelenmiş indeks, sayfa bölünmelerini ve parçalanmayı ( FILLFACTORs ile karıştırmadan) önlemek için rastgele olmayan (her yeni eklenen anahtar değer bir önceki değerden daha büyüktür) sırayla büyür .

Şimdi iyi bir kümelenmiş indeks anahtarının ne olduğunu bildiğimize göre, birincil anahtar (bir veri modelleme mantıksal özelliği olan) gereksinimlere uygun mu? Eğer evet ise, PK kümelenmelidir. Hayır ise, PK kümelenmemiş olmalıdır.

Bir örnek vermek gerekirse, bir satış gerçekleri tablosu düşünün. Her giriş, birincil anahtar olan bir kimliğe sahiptir. Ancak, sorguların büyük çoğunluğu bir tarih ile başka bir tarih arasında veri ister, bu nedenle en iyi kümelenmiş endeks anahtarı kimlik numarası değil satış tarihi olacaktır . Birincil anahtardan farklı kümelenmiş bir dizine sahip olmanın bir başka örneği, bir 'kategori' veya 'durum' gibi çok düşük bir seçicilik anahtarıdır, sadece çok az belirgin değere sahip bir anahtardır. En düşük anahtar olan bu düşük seçicilik anahtarına sahip kümelenmiş bir indeks anahtarına sahip olmak, örneğin , belirli bir 'durumdaki' tüm girişleri arayan aralıklar taramaları nedeniyle genellikle anlamlıdır.(state, id)

Bir öbek üzerinde kümelenmemiş bir birincil anahtarın olasılığı hakkında son bir not (yani, kümelenmiş bir dizin yoktur). Bu geçerli bir senaryo olabilir, tipik neden, yığın ekleme performansının kritik olmasıdır, çünkü yığınlar kümelenmiş endekslere kıyasla önemli ölçüde daha iyi yığın ekleme performansı sağlar.


1
Burada "gerekliliklere göre sırala, bir dizin bir dur-kalk sıralaması gerektirmeksizin bir siparişi yerine getirebiliyorsa" ne anlama geliyor?
Mike Sherrill 'Kedi Geri Çağırma'

2
@RemusRusanu. +1 Çok faydalı cevap. Örnek ile ilgili bir soru (state, id). Bu örnekte, "iyi kümelenmiş endeks rastgele değil sırayla büyür" gereksinimi karşılanmayacak, değil mi? Peki bunu kümelenmiş bir indeks olarak değerlendirebilir miyiz?
Lijo

26

Kümelenmiş dizinleri kullanmanın temel nedeni Wikipedia'da belirtilmiştir :

Kümeleme, veri bloğunu dizine uyması için belirli bir sıraya göre değiştirir ve satır verilerinin sırayla depolanmasına neden olur. Bu nedenle, belirli bir veritabanı tablosunda yalnızca bir kümelenmiş dizin oluşturulabilir. Kümelenmiş endeksler , genel geri alma hızını büyük ölçüde artırabilir, ancak genellikle verilere kümelenmiş dizinin aynı veya tersi sırayla veya bir dizi madde seçildiğinde sırayla erişildiğinde .

Diyelim ki bir insan masam var ve bu insanlar bir ülke sütunu ve benzersiz bir birincil anahtar var. Bu bir demografi tablosu, bu yüzden umurumda olan tek şey bunlar; Hangi ülke ve o ülkeye kaç tane eşsiz insan bağlı.

Bu nedenle yalnızca Ülke sütununu NEREDE veya SİPARİŞ VEREBİLİRSİNİZ; Birincil Anahtar üzerindeki kümelenmiş bir dizin bana hiç yardımcı olmuyor, bu verilere PK ile erişmiyorum, bu diğer sütuna erişiyorum. Bir tabloda kümelenmiş bir dizine sahip olabileceğim için PK'mı Kümelenmiş olarak bildirmek, Ülkede Kümelenmiş Dizin kullanmamı engeller.

Ayrıca, kümelenmiş ve kümelenmemiş dizinler hakkında iyi bir makale, kümelenmiş dizinler SQL Server 6.5 (en azından umarım burada çoğumuz için geçerli değil) eklemek performans sorunları neden çıktı ortaya çıkıyor.

Bir KİMLİK sütununa kümelenmiş bir dizin koyarsanız, tüm ekleriniz tablonun son sayfasında gerçekleşir - ve o sayfa her bir KİMLİK süresi boyunca kilitlenir. Önemli bir şey değil ... en son sayfayı isteyen 5000 kişi yoksa. O zaman bu sayfa için çok çekişmen var.

Daha sonraki sürümlerde durum böyle olmadığını unutmayın.


3
FIY, SQL Server 6.5'ten bahsettiniz: dba.stackexchange.com/questions/1584/…
gbn

15

Birincil anahtarınız ise, onun UNIQUEIDENTIFIERbelirttiğinizden emin olun NONCLUSTERED. Kümelendiriyorsanız, her bir satırın doğru pozisyonda yerleştirilmesi için her ara parçada bir grup kayıt yapılması gerekir. Bu tank performansını artıracak.


1
Kümelenmiş anahtarlar için UUID'lerden kaçınmaya çalışırken, yukarıda belirtilen nedenlerin eksik olabileceğine inanıyorum. SQL sunucusu mutlaka doğru pozisyona yerleştirmek için satırları değiştirmez ("düşük ve yüksek değerler arasında" demek istiyorsan). Bir trilyon sıra masasının ortasına bir uç düşünün. Ekstra dolaylılık, neyi kastettiğiniz olabilir. Sıralı bir UNIQUEIDENTIFIERtür de vardır ve yine de 128 boyuttan muzdarip olmasına rağmen, benzersiz anahtarlar oluşturma olasılığı aynıdır.
Charles Burns,

7

Çok yaygın bir örnek:

  • CustomerTablo sahip CustomerIDolarakCLUSTERED PRIMARY KEY
  • Sipariş tablosu OrderID (PK), CustomerID, OrderDateve diğer bazı sütunlar
  • OrderPositions ile OrderPositionID (PK), OrderId, ProductID, Amount, Price ...
  • Sipariş tablolarını indekslemeniz gerekir

Elbette "bağlıdır" - neredeyse her zaman olduğu gibi - doğru cevaptır, ancak çoğu uygulama (BI-Raporları değil) müşteri bazında çalışacaktır (örneğin, web sitesine müşteri 278 olarak giriş yapıp "Siparişlerim" üzerine tıklayın. Katip, müşteri 4569 için tüm siparişleri listeler veya fatura rutini müşteri için tüm siparişleri toplar (137).

Bu durumda, tabloyu kümelemek pek mantıklı olmazdı OrderID. Evet, SELECT ... WHERE OrderId = ?sipariş ayrıntılarını listelemek için sorularınız olacak , ancak bu genellikle kısa ve ucuz (3 okur) dizin arar.

Öte yandan, masanızı kümelendiriyorsanız, Ordertabloyu CustomerIDher sorguladığınızda birden fazla anahtar araması yapmak zorunda kalmazsınız CustomerId = ?.

Her CLUSTERED INDEXzaman olması gerekir UNIQUE, aksi takdirde SQL Server UNIQUIFIER, benzersizliği sağlamak için görünmez (= kullanılamaz) bir INT sütunu eklerdi - ve gerçek (kullanılabilir) verileri sonra bazı rasgele (ekleme sırasına bağlı olarak) şeyler eklemek çok daha anlamlı olurdu.

Bir müşteri (inşallah) birden fazla sipariş vereceğinden, ya OrderIDda (genellikle bunun için sıralama yaparsanız) OrderDate(eğer bir tarih ise - aksi takdirde müşteri günde bir siparişle sınırlı olacaktır) eklemek zorunda kalacağız. CLUSTERED INDEXve ile bitirmek:

CREATE UNIQUE CLUSTERED INDEX IX_Orders_UQ on Orders (CustomerID, OrderID)

Aynı kurallar OrderPositionstablo için de geçerlidir . Genellikle en çok yapılan sorgulamalar, tüm siparişleri belirli bir siparişte listeleyecektir, bu yüzden PK'yi OrderPositionIDas NONCLUSTEREDve a UNIQUE CLUSTERED INDEXile oluşturmalısınız OrderId, OrderPositionID.

BTW: Customertablonun PK'si tarafından kümelenmesi (bunun CustomerIDnedeni bir "Üst Düzey Tablosu" olduğu ve tipik bir uygulamada - çoğunlukla MüşteriNo tarafından sorgulanacağı doğru).

Ör olarak Saf arama Tablolar Gendersya InvoiceTypesya PaymentType(genellikle bunları katılmak olacak nedeniyle PK tarafından kümelenmiş gereken tablolardan başka bir örnektir GenderId, InvoiceTypeIdya PaymentTypeId).


2

Kümelenmiş bir indeks, bazı performans ölçütlerini kullanarak, kümelenmiş bir PK'dan daha genel sisteme daha faydalı olduğu düşünülürse. Bir tabloda yalnızca bir kümelenmiş dizin olabilir.

Örnek performans ölçütleri, tek sorgu süresi (hız), toplam sorgu sürelerinin tabloya karşı bütünleştirilmesi (verimlilik) ve kümelenmişe (boyutta) benzer bir performans elde etmek için çok büyük bir kümelenmemiş dizine bir sütun eklenmesi gerekmesidir. ).

Bu, veriler genellikle benzersiz olmayan, null içeren (bir PK'ye izin verilmez) bir dizin kullanılarak alındığında veya PK, ikincil bir nedenden dolayı (çoğaltma veya denetim izi kaydı tanımlaması gibi) eklendiğinde gerçekleşebilir.

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.