Tergugus vs Non-Gugus

98

Pengetahuan tingkat rendah saya tentang SQL (Server 2008) terbatas, dan sekarang sedang ditantang oleh DBA kami. Izinkan saya menjelaskan (saya telah menyebutkan pernyataan yang jelas dengan harapan saya benar, tetapi jika Anda melihat sesuatu yang salah, tolong beri tahu saya) skenarionya:

Kami memiliki meja yang berisi 'Perintah Pengadilan' untuk orang-orang. Ketika saya membuat tabel, (Name: CourtOrder), saya membuatnya seperti:

CREATE TABLE dbo.CourtOrder
(
  CourtOrderID INT NOT NULL IDENTITY(1,1), (Primary Key)
  PersonId INT NOT NULL,
  + around 20 other fields of different types.
)

Saya kemudian menerapkan indeks non-cluster ke kunci utama (untuk efisiensi). Alasan saya adalah bahwa ini adalah bidang unik (kunci utama), dan harus diindeks, terutama untuk tujuan pemilihan, seperti yang sering kita lakukan.Select from table where primary key = ...

Saya kemudian menerapkan indeks CLUSTERED di PersonId. Alasannya adalah mengelompokkan pesanan untuk orang tertentu secara fisik, karena sebagian besar pekerjaan mendapatkan pesanan untuk seseorang. Begitu,select from mytable where personId = ...

Saya telah ditarik sekarang. Saya telah diberitahu bahwa kita harus meletakkan indeks berkerumun pada kunci utama, dan indeks normal pada personId. Itu tampak sangat aneh bagiku. Pertama, mengapa Anda menempatkan indeks berkerumun di kolom unik? apa itu pengelompokan? Tentunya itu hanya pemborosan dari clustered index? Saya percaya indeks normal akan digunakan pada kolom unik. Juga, mengelompokkan indeks berarti kita tidak dapat mengelompokkan kolom yang berbeda (Satu per tabel, kan?).

Alasan saya diberi tahu bahwa saya telah melakukan kesalahan adalah karena mereka percaya bahwa menempatkan indeks berkerumun di PersonId akan membuat penyisipan menjadi lambat. Untuk peningkatan 5% dalam kecepatan pemilihan, kami akan mendapatkan penurunan 95% dalam kecepatan pada penyisipan dan pembaruan. Apakah itu benar dan valid?

Mereka mengatakan bahwa karena kita mengelompokkan personId, SQL Server harus mengatur ulang data setiap kali kita memasukkan atau membuat perubahan ke PersonId.

Jadi saya bertanya, mengapa SQL memiliki konsep CLUSTERED INDEX, jika sangat lambat? Apakah itu selambat yang mereka katakan? Bagaimana saya harus mengatur indeks saya untuk mencapai kinerja yang optimal? Saya mengira SELECT digunakan lebih dari INSERT ... tetapi mereka mengatakan bahwa kami mengalami masalah penguncian pada INSERTS ...

Semoga seseorang bisa membantu saya.

Craig
sumber

Jawaban:

117

Perbedaan antara indeks berkerumun vs. tidak berkerumun adalah bahwa indeks berkerumun menentukan urutan fisik baris dalam database . Dengan kata lain, menerapkan indeks berkerumun PersonIdberarti bahwa baris akan secara fisik diurutkan berdasarkan PersonIddalam tabel, memungkinkan pencarian indeks tentang ini untuk langsung ke baris (bukan indeks non-klaster, yang akan mengarahkan Anda ke baris lokasi, menambahkan langkah ekstra).

Meskipun demikian, tidak biasa jika kunci utama tidak menjadi indeks berkerumun, tetapi bukannya tidak pernah terdengar. Masalah dengan skenario Anda sebenarnya kebalikan dari apa yang Anda asumsikan: Anda menginginkan nilai unik dalam indeks berkerumun, bukan duplikat. Karena indeks berkerumun menentukan urutan fisik baris, jika indeks berada di kolom non-unik, server harus menambahkan nilai latar belakang ke baris yang memiliki nilai kunci duplikat (dalam kasus Anda, baris mana pun dengan nilai yang sama PersonId) sehingga nilai gabungan (key + background value) unik.

Satu-satunya hal yang saya sarankan adalah tidak menggunakan CourtOrderIdkolom kunci pengganti (Anda ) sebagai kunci utama, tetapi menggunakan kunci utama gabungan dariPersonId dan beberapa kolom atau kumpulan kolom pengenal unik lainnya. Jika itu tidak memungkinkan (atau tidak praktis), maka aktifkan indeks berkerumun CourtOrderId.

Adam Robinson
sumber
Terima kasih Adam. Jadi, kapan indeks berkerumun akan berguna? Saya pikir manfaatnya mengelompokkan indeks adalah mengelompokkan data, saat, misalnya, sebagian besar kueri ada di PersonID ... sehingga datanya akan dikelompokkan.
Craig
3
Itu tidak diurutkan secara fisik PersonId. Ini diurutkan secara logis berdasarkan PersonId, setiap perbedaan antara urutan logis dan fisik adalah tingkat fragmentasi logis.
Martin Smith
1
@cdotlister Manfaat indeks adalah untuk mengurutkan data, bukan mengelompokkannya (yang menyiratkan data duplikat dalam indeks). Meskipun perbedaannya mungkin tampak semantik, dalam kasus indeks berkerumun, perbedaannya tidak demikian. Jika memungkinkan, indeks berkerumun harus berada pada sesuatu yang secara unik mengidentifikasi baris, dan (idealnya) juga merupakan kolom atau kumpulan kolom yang paling sering ditanyakan. Inilah sebabnya mengapa biasanya ada di kunci utama.
Adam Robinson
1
@CyberSluethOmega: Saya tidak tahu; pertanyaan Anda tidak berisi informasi yang cukup bagi saya untuk mengambil keputusan. Apakah saya ingin indeks berkerumun pada sekumpulan kolom di mana baris akan sering ditambahkan atau dihapus selain di akhir tabel ? Tidak. Tapi saya tidak begitu yakin mengapa Anda menanyakan itu atau mengapa suara negatifnya.
Adam Robinson
1
@CyberSluethOmega: Internet dapat membuat komentar terdengar defensif atau dingin jika tidak dimaksudkan seperti itu. Anda mengklaim bahwa saya mengatakan bahwa saya tidak tahu keadaan di mana membuat indeks berkerumun sesuatu selain kunci utama, padahal sebenarnya saya tidak mengatakan hal seperti itu. Bahkan, apa yang saya katakan adalah "ini tidak biasa ..., tetapi tidak pernah terdengar", yang berarti bahwa saya tidak tahu kasus di mana hal ini dilakukan.
Adam Robinson
14

Saya sama sekali bukan Ahli SQL ... jadi anggap ini sebagai pandangan pengembang daripada tampilan DBA ..

Sisipan pada indeks berkerumun (diurutkan secara fisik) yang tidak dalam urutan berurutan menyebabkan pekerjaan tambahan untuk penyisipan / pembaruan. Juga, jika Anda memiliki banyak penyisipan yang terjadi sekaligus dan semuanya terjadi di lokasi yang sama, Anda berakhir dengan pertengkaran. Performa spesifik Anda bervariasi berdasarkan data Anda dan cara Anda mengaksesnya. Aturan umumnya adalah membangun indeks berkerumun Anda pada nilai sempit paling unik di tabel Anda (biasanya PK)

Saya berasumsi PersonId Anda tidak akan berubah, jadi Pembaruan tidak ikut bermain di sini. Tetapi pertimbangkan snapshot dari beberapa baris dengan PersonId 1 2 3 3 4 5 6 7 8 8

Sekarang masukkan 20 baris baru untuk PersonId 3. Pertama, karena ini bukan kunci unik, server menambahkan beberapa byte ekstra ke nilai Anda (di belakang layar) untuk membuatnya unik (yang juga menambahkan ruang ekstra) dan kemudian lokasi di mana ini akan tinggal harus diubah. Bandingkan itu dengan memasukkan PK yang bertambah otomatis di mana penyisipan terjadi di akhir. Penjelasan non teknis kemungkinan besar akan menjadi seperti ini: ada lebih sedikit pekerjaan 'pengocokan daun' yang harus dilakukan jika secara alami meningkatkan nilai yang lebih tinggi di akhir tabel versus lokasi pengerjaan ulang item yang ada di lokasi itu sambil memasukkan item Anda.

Sekarang, jika Anda mengalami masalah dengan Sisipan, kemungkinan besar Anda akan memasukkan sekumpulan nilai PersonId yang sama (atau serupa) sekaligus yang menyebabkan pekerjaan tambahan ini di berbagai tempat di seluruh tabel dan fragmentasi membunuh Anda. Kelemahan dari beralih ke PK yang dikelompokkan dalam kasus Anda, adalah jika Anda mengalami masalah penyisipan hari ini di PersonIds yang nilainya bervariasi yang tersebar di seluruh tabel, jika Anda mengalihkan indeks berkerumun Anda ke PK dan semua penyisipan sekarang terjadi dalam satu lokasi maka masalah Anda mungkin benar-benar menjadi lebih buruk karena peningkatan konsentrasi pertengkaran. (Di sisi lain, jika sisipan Anda hari ini tidak tersebar di seluruh, tetapi semuanya biasanya berkumpul di area yang sama, maka masalah Anda kemungkinan akan berkurang dengan mengalihkan indeks berkerumun Anda dari PersonId ke PK karena Anda akan meminimalkan fragmentasi.)

Masalah kinerja Anda harus dianalisis sesuai dengan situasi unik Anda dan menjadikan jenis jawaban ini sebagai pedoman umum saja. Taruhan terbaik Anda adalah mengandalkan DBA yang dapat memvalidasi dengan tepat di mana letak masalah Anda. Sepertinya Anda memiliki masalah pertentangan sumber daya yang mungkin di luar penyesuaian indeks sederhana. Ini bisa jadi merupakan gejala dari masalah yang jauh lebih besar. (Kemungkinan masalah desain ... jika tidak, keterbatasan sumber daya.)

Bagaimanapun, semoga berhasil!

Darian Miller
sumber
5

Beberapa penulis menyarankan untuk tidak "menyia-nyiakan" CIpadaidentity kolom jika ada alternatif yang akan menguntungkan query jangkauan.

Dari MSDN Clustered Index Design Guidelines , kunci harus dipilih sesuai dengan kriteria berikut

  1. Dapat digunakan untuk kueri yang sering digunakan.
  2. Memberikan keunikan yang tinggi.
  3. Dapat digunakan dalam kueri rentang.

CourtOrderIDKolom Anda bertemu 2. Anda PersonIdbertemu 1dan 3. Karena sebagian besar baris akan berakhir dengan uniqueifierpenambahan, Anda mungkin juga menyatakannya sebagai unik dan bergunaPersonId,CourtOrderID karena ini akan memiliki lebar yang sama tetapi akan lebih berguna karena kunci indeks berkerumun ditambahkan ke semua NCI sebagai pencari baris dan ini akan memungkinkan mereka untuk mencakup lebih banyak pertanyaan.

Masalah utama dengan menggunakan PersonId,CourtOrderIDsebagai CI adalah bahwa fragmentasi logis kemungkinan besar akan terjadi (dan ini terutama memengaruhi kueri rentang yang Anda coba bantu) sehingga Anda perlu memantau faktor pengisian, dan tingkat fragmentasi serta melakukan pemeliharaan indeks lebih sering.

Martin Smith
sumber
3

Ini dijelaskan di tautan berikut: https://msdn.microsoft.com/en-us/ms190457.aspx

Berkelompok

  • Indeks tergugus mengurutkan dan menyimpan baris data dalam tabel atau tampilan berdasarkan nilai utamanya. Ini adalah kolom yang termasuk dalam definisi indeks. Hanya ada satu indeks berkerumun per tabel, karena baris datanya sendiri hanya dapat diurutkan dalam satu urutan.

  • Satu-satunya saat baris data dalam tabel disimpan dalam urutan yang diurutkan adalah saat tabel berisi indeks berkerumun. Ketika tabel memiliki indeks berkerumun, tabel tersebut disebut tabel berkerumun. Jika tabel tidak memiliki indeks berkerumun, baris datanya disimpan dalam struktur tak berurutan yang disebut heap.

Tidak terkluster

  • Indeks yang tidak terkluster memiliki struktur yang terpisah dari baris data. Sebuah indeks nonclustered c ontains nilai kunci indeks nonclustered dan setiap entri nilai kunci memiliki pointer ke baris data yang berisi nilai kunci .

  • Penunjuk dari baris indeks dalam indeks nonclustered ke baris data disebut pencari baris. Struktur pencari baris bergantung pada apakah halaman data disimpan dalam tumpukan atau tabel berkerumun. Untuk heap, pencari baris adalah penunjuk ke baris. Untuk tabel berkerumun, pencari baris adalah kunci indeks berkerumun.

  • Anda dapat menambahkan kolom nonkunci ke tingkat daun dari indeks nonclustered untuk melewati batas kunci indeks yang ada, 900 byte dan 16 kolom kunci, dan menjalankan kueri yang sepenuhnya tercakup, terindeks.

pengguna2191454
sumber
-3

Beberapa db dengan beberapa pilihan buruk, bergabung dalam prosedur tersimpan - hanya perbedaannya adalah indeks

INDEKS - clustered vs nonclustered

  891 rows
  10 sec
  NONCLUSTERED 

  OR

  891 rows
  14 sec
  CLUSTERED
toLucky
sumber