Kapan kunci primer harus dinyatakan non-cluster?

169

Saat membuat database uji untuk pertanyaan lain yang saya ajukan sebelumnya, saya ingat tentang Kunci Utama yang dapat dideklarasikan NONCLUSTERED

Kapan Anda akan menggunakan NONCLUSTEREDkunci utama yang bertentangan dengan CLUSTEREDkunci primer?

Terima kasih sebelumnya

Stuart Blackler
sumber

Jawaban:

188

Pertanyaannya bukan 'kapan PK harus NC', tetapi Anda harus bertanya 'apa kunci yang tepat untuk indeks berkerumun'?

Dan jawabannya sangat tergantung pada bagaimana Anda meminta data . Indeks berkerumun memiliki keunggulan dibandingkan semua indeks lain: karena selalu mencakup semua kolom, selalu mencakup. Oleh karena itu pertanyaan yang dapat memanfaatkan indeks berkerumun tentu tidak perlu menggunakan pencarian untuk memenuhi beberapa kolom yang diproyeksikan dan / atau predikat.

Bagian lain dari teka-teki adalah bagaimana indeks dapat digunakan ? Ada tiga pola khas:

  • probe, ketika nilai kunci tunggal dicari dalam indeks
  • rentang pemindaian, ketika rentang nilai kunci diambil
  • memesan dengan persyaratan, ketika indeks dapat memenuhi pesanan dengan w / o membutuhkan semacam stop-and-go

Jadi, jika Anda menganalisis beban yang diharapkan (kueri) dan menemukan bahwa sejumlah besar kueri akan menggunakan indeks tertentu karena mereka menggunakan pola akses tertentu yang diuntungkan dari indeks, masuk akal untuk mengajukan indeks itu sebagai indeks berkerumun.

Namun faktor lain adalah bahwa kunci indeks berkerumun adalah kunci pencarian yang digunakan oleh semua indeks yang tidak berkerumun dan karena itu kunci indeks berkerumun luas menciptakan efek riak dan memperluas semua indeks yang tidak berkerumun dan indeks lebar berarti lebih banyak halaman, lebih banyak I / O , lebih banyak memori, lebih sedikit kebaikan.

Indeks berkerumun yang baik stabil , itu tidak berubah selama masa entitas, karena perubahan nilai kunci indeks berkerumun berarti baris harus dihapus dan dimasukkan kembali.

Dan indeks berkerumun yang baik tumbuh agar tidak secara acak (setiap nilai kunci yang baru dimasukkan lebih besar dari nilai sebelumnya) untuk menghindari pemisahan halaman dan fragmentasi (tanpa bermain-main dengan FILLFACTORs).

Jadi sekarang kita tahu apa kunci indeks berkerumun yang baik, apakah kunci utama (yang merupakan properti logis pemodelan data) cocok dengan persyaratan? Jika ya, maka PK harus dikelompokkan. Jika tidak, maka PK harus non-cluster.

Untuk memberikan contoh, pertimbangkan tabel fakta penjualan. Setiap entri memiliki ID yang merupakan kunci utama. Tetapi sebagian besar pertanyaan meminta data antara tanggal dan tanggal lain, oleh karena itu kunci indeks terkluster terbaik adalah tanggal penjualan , bukan ID . Contoh lain dari memiliki indeks pengelompokan berbeda dari kunci primer adalah kunci selektivitas yang sangat rendah, seperti 'kategori', atau 'keadaan', kunci dengan hanya beberapa nilai berbeda. Memiliki kunci indeks berkerumun dengan kunci selektivitas rendah ini sebagai kunci paling kiri, misalnya (state, id), sering masuk akal karena pemindaian rentang yang mencari semua entri dalam 'keadaan' tertentu.

Satu catatan terakhir tentang kemungkinan kunci primer non-cluster di atas heap (yaitu tidak ada indeks cluster sama sekali). Ini mungkin skenario yang valid, alasan khasnya adalah ketika kinerja penyisipan massal sangat penting, karena tumpukan memiliki throughput penyisipan massal yang jauh lebih baik bila dibandingkan dengan indeks yang dikelompokkan.

Remus Rusanu
sumber
1
Apa yang dimaksud dengan "memesan berdasarkan persyaratan, ketika indeks dapat memenuhi pesanan dengan tidak memerlukan semacam stop-and-go" di sini?
Mike Sherrill 'Cat Recall'
2
@RemusRusanu. +1 jawaban yang sangat berguna. Satu pertanyaan tentang contoh itu (state, id). Dalam contoh ini, "indeks cluster yang baik tumbuh agar tidak secara acak" persyaratan tidak akan dipenuhi, bukan? Jadi bisakah kita menganggapnya sebagai indeks berkerumun yang baik?
LCJ
26

Alasan dasar untuk menggunakan indeks Clustered dinyatakan di Wikipedia :

Clustering mengubah blok data ke dalam urutan berbeda tertentu agar sesuai dengan indeks, menghasilkan data baris yang disimpan secara berurutan. Oleh karena itu, hanya satu indeks berkerumun dapat dibuat pada tabel database yang diberikan. Indeks yang dikelompokkan dapat sangat meningkatkan kecepatan pengambilan secara keseluruhan, tetapi biasanya hanya jika data diakses secara berurutan dalam urutan yang sama atau terbalik dari indeks yang dikelompokkan , atau ketika berbagai item dipilih.

Katakan bahwa saya memiliki tabel Orang, dan orang-orang ini memiliki kolom Negara dan Kunci Utama yang unik. Ini adalah tabel demografi, jadi ini adalah satu-satunya hal yang saya pedulikan; Negara apa dan berapa banyak orang unik yang terikat pada negara itu.

Dengan demikian, saya hanya akan cenderung untuk MEMILIH DIMANA atau MEMESAN OLEH kolom Negara; indeks berkerumun pada Kunci Utama tidak ada gunanya bagiku, aku tidak mengakses data ini dengan PK, aku mengaksesnya dengan kolom lain ini. Karena saya hanya dapat memiliki satu indeks berkerumun di atas meja, menyatakan PK saya sebagai Berkelompok akan mencegah saya menggunakan Indeks Berkelompok di Negara.

Selain itu, inilah artikel yang bagus tentang Indeks Clustered vs Nonclustered , ternyata indeks clustered menyebabkan masalah kinerja penyisipan di SQL Server 6.5 (yang setidaknya semoga tidak relevan bagi kebanyakan dari kita di sini).

Jika Anda meletakkan indeks berkerumun di kolom IDENTITY, maka semua sisipan Anda akan terjadi pada halaman terakhir tabel - dan halaman itu dikunci selama durasi setiap IDENTITY. Bukan masalah besar ... kecuali jika Anda memiliki 5000 orang yang semuanya menginginkan halaman terakhir. Maka Anda memiliki banyak pertengkaran untuk halaman itu

Perhatikan bahwa ini tidak terjadi di versi yang lebih baru.

Ben Brocka
sumber
3
FIY, Anda menyebutkan SQL Server 6.5: dba.stackexchange.com/questions/1584/…
gbn
15

Jika kunci utama Anda dari UNIQUEIDENTIFIER, pastikan untuk menentukan bahwa itu NONCLUSTERED. Jika Anda membuatnya berkerumun, setiap sisipan harus melakukan banyak pengocokan catatan untuk menyisipkan baris baru di posisi yang benar. Ini akan menurunkan kinerja.

Bryan Johns
sumber
1
Sementara saya mencoba menghindari UUID untuk kunci berkerumun, saya percaya alasan di atas mungkin tidak lengkap. SQL server tidak harus merombak baris untuk menyisipkan ke posisi yang benar (jika Anda maksudkan "antara nilai yang lebih rendah dan lebih tinggi"). Pertimbangkan memasukkan ke tengah tabel baris triliun. Dibutuhkan tipuan ekstra, yang mungkin Anda maksudkan. UNIQUEIDENTIFIERTipe berurutan juga ada, dan memiliki probabilitas yang sama untuk menghasilkan kunci unik, meskipun masih memiliki ukuran 128.
Charles Burns
8

Contoh yang sangat umum:

  • Customermeja dengan CustomerIDasCLUSTERED PRIMARY KEY
  • Tabel pesanan dengan OrderID (PK), CustomerID, OrderDatedan beberapa kolom lainnya
  • OrderPositions dengan OrderPositionID (PK), OrderId, ProductID, Amount, Price ...
  • Anda harus mengindeks tabel Orde

Tentu saja "itu tergantung" adalah - seperti hampir selalu - jawaban yang benar, tetapi sebagian besar aplikasi (bukan BI-Laporan) akan berfungsi berdasarkan pelanggan (misalnya Anda login sebagai pelanggan 278 ke situs web dan klik ke "Pesanan saya" atau Petugas mendaftar semua pesanan untuk pelanggan 4569 atau rutin faktur Anda akan meringkas semua pesanan untuk pelanggan 137).

Dalam hal ini tidak masuk akal untuk mengelompokkan tabel dengan OrderID. Ya, Anda akan memiliki pertanyaan tentang SELECT ... WHERE OrderId = ?daftar detail pesanan, tetapi biasanya indeks ini pendek dan murah (3 kali dibaca).

Di sisi lain, jika Anda akan mengelompokkan Ordertabel Anda dengan CustomerID, itu tidak harus melakukan pencarian kunci ganda setiap kali Anda meminta tabel untuk CustomerId = ?.

The CLUSTERED INDEXharus selalu UNIQUE, jika SQL Server akan menambahkan (= tidak dapat digunakan) kolom INT tak terlihat UNIQUIFIERuntuk memastikan uniquiness - dan itu akan lebih masuk akal untuk menambahkan nyata data (digunakan) kemudian beberapa acak (tergantung pada urutan Memasukkan) hal.

Karena pelanggan akan (semoga) melakukan lebih dari satu pesanan, kami harus menambahkan salah satu OrderIDatau (jika Anda mengurutkan untuk ini) the OrderDate(jika ini adalah waktu - - jika pelanggan akan dibatasi untuk satu pesanan per hari) untuk yang CLUSTERED INDEXdan berakhir dengan:

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

Aturan yang sama berlaku untuk OrderPositionstabel. Biasanya pertanyaan paling banyak akan mencantumkan semua posisi untuk pada urutan tertentu, jadi Anda harus membuat PK dengan OrderPositionIDas NONCLUSTEREDdan UNIQUE CLUSTERED INDEXon OrderId, OrderPositionID.

BTW: benar bahwa Customertabel dikelompokkan oleh PK-nya ( CustomerIDkarena, itu adalah "Top-Level-Table" dan akan - dalam aplikasi yang khas - sebagian besar dipertanyakan oleh CustomerID-nya.

Tabel lookup murni seperti misalnya Gendersatau InvoiceTypesatau PaymentTypeadalah contoh lain dari tabel yang harus dikelompokkan dengan PK-nya (karena Anda biasanya akan bergabung dengannya GenderId, InvoiceTypeIdatau PaymentTypeId).

Thomas Franz
sumber
2

Ketika indeks berkerumun dianggap lebih bermanfaat bagi sistem keseluruhan daripada PK berkerumun dengan menggunakan beberapa ukuran kinerja. Hanya ada satu indeks berkerumun di atas meja.

Contoh ukuran kinerja adalah waktu kueri tunggal (kecepatan), integrasi waktu kueri total terhadap tabel (efisiensi) dan harus menambahkan banyak kolom termasuk ke indeks non-cluster yang sangat besar untuk mencapai kinerja yang mirip dengan clustered (ukuran ).

Ini dapat terjadi ketika data umumnya diambil menggunakan indeks yang tidak unik, berisi nulls (tidak diizinkan dalam PK), atau PK ditambahkan untuk alasan sekunder (seperti replikasi atau identifikasi catatan jejak audit).

crokusek
sumber