Haruskah indeks pada kolom identitas nonclustered?

19

Untuk tabel dengan kolom identitas, haruskah PK / indeks unik berkerumun atau tidak berkerumun dibuat untuk kolom identitas?

Alasannya adalah indeks lain akan dibuat untuk kueri. Kueri yang menggunakan indeks nonclustered (di heap) dan mengembalikan kolom yang tidak tercakup oleh indeks akan menggunakan I / O (LIO) yang kurang logis karena tidak ada indeks clustered tambahan b-tree mencari langkah-langkah?

create table T (
  Id int identity(1,1) primary key, -- clustered or non-clustered? (surrogate key, may be used to join another table)
  A .... -- A, B, C have mixed data type of int, date, varchar, float, money, ....
  B ....
  C ....
  ....)

create index ix_A on T (A)
create index ix_..... -- Many indexes can be created for queries

-- Common query is query on A, B, C, ....
select A, B 
from T 
where A between @a and @a+5 -- This query will have less LIO if the PK is non-clustered (seek)

select A, B, C
from T 
where B between @a and @a+5 

....

PK yang dikelompokkan pada kolom identitas baik karena:

  1. Ini meningkat secara monoton sehingga tidak ada halaman yang terbelah saat memasukkan. Dikatakan insert massal bisa secepat pada tabel heap (nonclustered)

  2. Itu sempit

Namun, apakah pertanyaan dalam pertanyaan akan lebih cepat tanpa mengaturnya berkerumun?

** Pembaruan: ** Bagaimana jika itu Idadalah FK dari tabel lain dan akan bergabung dalam beberapa pertanyaan?

u23432534
sumber
3
Itu tidak lebih baik atau lebih buruk, itu tergantung.
Aaron Bertrand
1
@ypercube Tautan kejser.org/clustered-indexes-vs-heaps mengatakan bahwa non-CI akan memiliki LIO yang lebih sedikit.
u23432534
2
Saya telah membaca artikel di masa lalu dan tentu saja menunjukkan bahwa ada kasus untuk indeks berkerumun dan kasus untuk tumpukan. Tidak semuanya hitam atau putih.
ypercubeᵀᴹ
4
Saya tidak yakin respons Anda terhadap @ypercube memenuhi semua kriteria yang dikutip oleh Mr. Kejser - setidaknya dengan detail yang Anda bagikan. Dalam bentuk saat ini, saya tidak benar-benar yakin bahwa ini akan menghasilkan jawaban yang bermanfaat karena harus mencakup hampir setiap skenario tunggal - yang sudah dilakukan di posting blog yang Anda kutip. Jika Anda dapat memberikan rincian lebih lanjut tentang skenario spesifik Anda, maka mungkin beberapa pengetahuan dalam posting dapat diterapkan.
swasheck
2
Ini akan tergantung pada hal-hal seperti: a) beban kerja (OLTP? OLAP? Dll?), B) ukuran tabel, c) bentuk normal, hanya untuk beberapa nama. Anda belum memberikan detail mengenai faktor-faktor ini sehingga rekomendasi apa pun akan didasarkan pada tebakan dari lingkungan Anda. Juga, sudahkah Anda mencoba membuat profil kueri yang Anda usulkan (dengan buffer yang dihapus) dan mendapatkan profil IO spesifik per konfigurasi dan melihatnya sendiri?
swasheck

Jawaban:

16

Secara default PK dikelompokkan dan dalam kebanyakan kasus, ini baik-baik saja. Namun, pertanyaan mana yang harus ditanyakan:

  • haruskah PK saya dikelompokkan?
  • kolom manakah yang akan menjadi kunci terbaik untuk indeks berkerumun saya?

Indeks PK dan Clustered adalah 2 perbedaan:

  • PK adalah kendala. PK digunakan untuk mengidentifikasi baris secara unik, tetapi tidak ada gagasan penyimpanan. Namun secara default (dalam SSMS), ini diberlakukan oleh indeks berkerumun unik jika indeks berkerumun belum ada.
  • Indeks Clustered adalah jenis indeks khusus yang menyimpan data baris pada tingkat daun, yang berarti selalu meliputi. Semua kolom apakah itu bagian dari kunci atau tidak, disimpan pada tingkat daun. Itu tidak harus unik, dalam hal ini uniquifier (4 byte) ditambahkan ke kunci berkerumun.

Sekarang kita berakhir dengan 2 pertanyaan:

  • Bagaimana saya ingin secara unik mengidentifikasi baris di tabel saya (PK)
  • Bagaimana saya ingin menyimpannya pada tingkat daun indeks (Clustered Index)

Tergantung bagaimana:

  • Anda merancang model data Anda
  • Anda meminta data Anda dan Anda menulis pertanyaan Anda
  • Anda memasukkan atau memperbarui data Anda
  • ...

Pertama, apakah Anda memerlukan indeks berkerumun? Jika Anda memasukkan massal, lebih efisien untuk menyimpan data yang tidak terurut ke HEAP (dibandingkan data yang dipesan dalam sebuah cluster). Ini menggunakan RID (Pengidentifikasi Baris, 8 byte) untuk secara unik mengidentifikasi baris dan menyimpannya di halaman.

Indeks yang dikelompokkan tidak boleh berupa nilai acak. Data di tingkat daun akan disimpan dan dipesan oleh kunci indeks. Karena itu ia harus tumbuh terus menerus untuk menghindari fragmentasi atau pemisahan halaman. Jika ini tidak dapat dicapai oleh PK, Anda harus mempertimbangkan kunci lain sebagai kandidat berkerumun. Indeks yang dikelompokkan pada kolom identi, GUID berurutan atau bahkan sesuatu seperti tanggal penyisipan baik-baik saja dari sudut pandang sekuensial karena semua baris akan ditambahkan ke halaman daun terakhir. Di sisi lain, sementara pengidentifikasi unik mungkin berguna untuk kebutuhan bisnis Anda sebagai PK, mereka tidak boleh dikelompokkan (mereka secara acak dipesan / dihasilkan).

Jika setelah beberapa data dan analisis kueri, Anda mengetahui bahwa Anda sebagian besar menggunakan indeks yang sama untuk mendapatkan data Anda sebelum melakukan pencarian kunci di PK berkerumun, Anda dapat menganggapnya sebagai indeks berkerumun meskipun mungkin tidak secara unik mengidentifikasi data Anda.

Kunci indeks berkerumun terdiri dari semua kolom yang ingin Anda indeks. Kolom unik (4 byte) ditambahkan jika tidak ada batasan unik di atasnya (nilai inkremental untuk duplikat, nol sebaliknya). Kunci indeks ini kemudian akan disimpan satu kali untuk setiap baris di tingkat daun dari semua indeks yang tidak tercakup. Beberapa dari mereka juga akan disimpan beberapa kali pada tingkat menengah (cabang) antara akar dan tingkat daun pohon indeks (pohon-B). Jika kunci terlalu besar, semua indeks yang tidak berkerumun akan menjadi lebih besar, akan membutuhkan lebih banyak penyimpanan dan lebih banyak IO, CPU, memori, ... Jika Anda memiliki PK pada nama + tanggal lahir + negara, sangat mungkin bahwa kunci ini bukan kandidat yang baik. Itu terlalu besar untuk indeks berkerumun. Uniqueidentifier menggunakan NEWSEQUENTIALID () biasanya tidak dianggap sebagai kunci sempit (16 byte) meskipun berurutan.

Kemudian setelah Anda menemukan cara mengidentifikasi baris secara unik di tabel Anda, Anda bisa menambahkan PK. Jika Anda pikir Anda tidak akan menggunakannya dalam permintaan Anda, jangan buat itu berkerumun. Anda masih dapat membuat indeks nonclustered lain jika suatu saat Anda perlu menanyakannya. Perhatikan bahwa PK akan secara otomatis membuat indeks unik.

Indeks yang tidak dikelompokkan akan selalu berisi kunci yang dikelompokkan. Namun, jika kolom yang diindeks (+ kolom kunci) mencakup, tidak akan ada pencarian kunci dalam indeks berkerumun. Jangan lupa Anda juga dapat menambahkan Sertakan dan Di mana ke indeks yang tidak berkerumun. (Gunakan dengan bijak)

Indeks Clustered harus unik dan sesempit mungkin. Indeks Clustered tidak boleh berubah dari waktu ke waktu dan harus dimasukkan secara bertahap.

Sekarang saatnya untuk menulis beberapa SQL yang akan membuat tabel, indeks clustered dan nonclustered dan kendala.

Ini semua teoretis karena kami tidak tahu model data dan tipe data Anda yang digunakan (A dan B).

Julien Vavasseur
sumber
11

Untuk tabel dengan kunci utama (PK) pada kolom identitas, itu akan dikelompokkan secara default. Mungkinkah lebih baik sebagai nonclustered?

Jika Anda bertanya apakah default untuk kunci utama pada kolom identitas (khususnya) harus nonclustered, saya akan mengatakan tidak. Sebagian besar tabel mendapat manfaat dari memiliki indeks berkerumun, jadi membuat standar berkerumun untuk batasan kunci primer mungkin membantu secara keseluruhan, terutama untuk pengguna baru SQL Server.

Seperti halnya hampir semua opsi, selalu ada keadaan yang berbeda di mana satu lebih disukai daripada yang lain, tetapi DBA yang berpengalaman harus menyadari default, dan dapat menimpanya jika perlu. Lihat juga Tanya Jawab terkait, Kapan kunci primer harus dinyatakan nonclustered? .

Apakah pertanyaan dalam pertanyaan akan lebih cepat tanpa mengaturnya berkerumun?

Ya, tetapi dengan peringatan.

Pencarian RID memang lebih efisien daripada pencarian Kunci. Bahkan jika semua halaman yang diperlukan dalam memori (sangat mungkin untuk tingkat atas indeks), ada biaya CPU yang terkait dengan menavigasi indeks b-tree clustered. Sebagai akibatnya, SQL Server biasanya dapat melakukan pencarian RID lebih banyak daripada pencarian Kunci per unit waktu CPU.

Peringatan

Hal di atas tidak sering menjadi faktor penentu ketika memutuskan apakah akan menyusun tabel sebagai tumpukan atau tidak. Harus tidak praktis untuk menghindari pencarian (menggunakan indeks penutup), dan jumlah pencarian harus cukup besar untuk memiliki efek yang terukur (dan penting) pada kinerja, mengingat lingkungan perangkat keras dan beban kerja.

Tidak benar-benar praktis untuk mencakup semua aspek dari debat heap vs clustered index dalam jawaban ini, tetapi saya akan mengatakan bahwa ada beberapa alasan bagus untuk lebih memilih untuk menyusun tabel sebagai heap secara umum. Bagi saya, memilih jenis desain yang diusulkan dalam pertanyaan akan memerlukan analisis yang sangat hati-hati sebelum implementasi, dan harus memenuhi standar yang tinggi. Argumen umum tentang 'skalabilitas' tidak akan cukup.

Mengenai pembaruan untuk pertanyaan tentang bergabung, menilai dampak kehilangan indeks berkerumun pada rencana pelaksanaan akan menjadi bagian dari analisis yang disebutkan di atas. Jika nested loops joins digunakan, sangat nyaman untuk memiliki indeks berkerumun pada kunci gabungan karena semua kolom dari baris segera tersedia tanpa pencarian.

Pengalaman saya sendiri adalah bahwa memiliki indeks pengelompokan unik pada kolom identitas sering kali bermanfaat, semua hal dipertimbangkan. Saya telah menemukan tumpukan bermasalah dalam hal manajemen ruang, dan saya juga harus menyebutkan bahwa beberapa fitur SQL Server memerlukan indeks berkerumun unik untuk berfungsi.

Paul White mengatakan GoFundMonica
sumber
8

Sebenarnya, Anda tidak perlu Indeks Berkelompok atau Kunci Utama untuk dibuat, karena Indeks Unik dan Indeks Non-Unik dapat menangani pekerjaan. SQL Server telah mendukung Indeks Clustered sejak setidaknya versi 1.1, tetapi Kunci Primer hanyalah sebuah "konsep" yang diprogram oleh pemrogram dengan mendefinisikan indeks yang unik.

Tapi sepertinya Primary Key dan Clustered Indexes adalah konsep yang berharga di sebagian besar basis data.

Mari kita lihat dokumentasi SQL Server untuk melihat deskripsi sebagian dari beberapa opsi pengindeksan seperti yang ditunjukkan di bawah ini.

Indeks Clustered: https://msdn.microsoft.com/en-us/library/ms190457.aspx

  • Indeks yang dikelompokkan mengurutkan dan menyimpan baris data dalam tabel atau tampilan berdasarkan nilai kunci mereka. Ini adalah kolom yang termasuk dalam definisi indeks.
  • Hanya ada satu indeks berkerumun per tabel

Kunci Utama: https://msdn.microsoft.com/en-us/library/ms190457.aspx

  • Sebuah tabel hanya dapat berisi satu kendala PRIMARY KEY.

  • Semua kolom yang didefinisikan dalam batasan PRIMARY KEY harus didefinisikan sebagai NOT NULL.

  • Kunci Utama dapat dibuat sebagai Indeks Clustered (default jika tidak ada Indeks Clustered) atau Indeks Non-Clustered.

Indeks Unik: https://msdn.microsoft.com/en-us/library/ms187019.aspx

  • Saat Anda membuat batasan UNIQUE, indeks nonclustered unik dibuat untuk menegakkan batasan UNIQUE secara default.

  • Anda bisa menentukan Indeks Clustered UNIK jika Indeks Clustered belum ada untuk tabel.

Ini berarti bahwa pertanyaan Anda tentang Indeks Berkelompok dan Kunci Utama sebenarnya tentang beberapa masalah berikut. Harap dicatat bahwa tidak setiap tabel mendapat manfaat dari paket pengindeksan yang sama.

Kapan saya akan mendapat manfaat dari Kunci Utama yang terpisah dari Indeks Berkelompok?

Mungkin ketika Indeks Clustered adalah Lebar (misalnya, 5 kolom informasi tekstual, tetapi Kunci Utama kecil (INT atau BIGINT), seperti yang tampaknya Anda gambarkan.

  • Indeks Clustered luas akan memungkinkan Anda untuk dengan cepat memilih baris dari indeks untuk subset kueri yang memberikan jawaban serial dari Indeks Clustered (juga dikenal sebagai Tabel ). Misalnya, Indeks Clustered 5-kolom akan mendukung pemindaian kolom C1, C2, C3, C4, C5 atau C1, C2, C3, C4 dan seterusnya ke C1.
  • Catatan: Jika barisnya besar, ini mungkin memberi Anda beberapa keuntungan kecepatan dalam memilih rangkaian serial baris, terutama jika kolom lain dalam tabel secara teratur termasuk dalam set hasil.
  • Dalam hal ini Anda dapat menggunakan Kunci Utama untuk integritas referensial untuk memasok nilai yang dibutuhkan sebagai Kunci Asing untuk membatasi baris di tabel lain. PK kecil dan dengan demikian FK adalah hit kecil pada ukuran tabel yang direferensikan.
  • Namun, perhatikan bahwa indeks apa pun yang dibuat pada tabel yang memiliki Indeks Clustered akan mencakup semua kolom cluster di indeks lain yang Anda buat di tabel ini. Indeks Clustered luas akan memperluas ukuran semua indeks non-cluster di tabel itu.

Haruskah Anda membuat Kunci Utama saja menjadi Indeks Berkelompok?

  • Jika Anda memiliki Kunci Utama kecil (INT atau BIGINT) dan itu adalah Indeks Clustered, overhead kolom cluster relatif kecil. Meskipun Kunci Utama Clustered dalam kasus ini juga akan ada di setiap indeks pada tabel ini, itu adalah harga yang lebih kecil untuk dibayar daripada Wide Cluster yang dibahas di atas.

  • Indeks Klaster Kunci Utama ini biasanya tidak secara langsung menawarkan jalur mudah untuk memilih banyak baris secara serial.

  • Sekarang Anda telah membuat Kunci Utama Clustered, bagaimana dengan kolom-kolom lain yang pernah Anda rencanakan untuk dimasukkan dalam Indeks Clustered ?

  • Buat indeks Unik (atau Non-Unik) sesuai kebutuhan untuk mengindeks kriteria pencarian luas kolom C1, C2, C3, C4, C5. Nilai-nilai dalam Indeks "Imitasi Berkelompok" ini dapat berfungsi sebagai jalur pencarian yang lebih cepat untuk 5 kolom tersebut. Jika ada satu atau dua kolom yang tidak diindeks yang secara teratur dipilih juga, mereka dapat dimasukkan dalam indeks dengan INCLUDE (Doctor_Name, Diagnosis_Synopsis).

Meskipun saya menemukan Indeks Clustered sederhana dan Kunci Utama berguna, ada beberapa alasan bagus untuk memikirkan apakah akan menggunakannya dalam tabel atau dalam database.

Apakah Anda memerlukan Indeks Clustered sama sekali?

  • Jika Anda membuat indeks (Indeks Unik dan Indeks Non-Unik) dan mendefinisikan Kunci Utama tanpa overhead menjadi Indeks Clustered, Anda mungkin menemukan bahwa indeks yang lebih sempit menyediakan apa yang Anda butuhkan untuk pertanyaan Anda.

  • Ada beberapa perilaku bermanfaat dalam Indeks Berkelompok dan Kunci Utama, tetapi ingat bahwa sebenarnya indekslah yang paling penting. Rancang strategi pengindeksan untuk memperhitungkan realitas aplikasi Anda. Mungkin OneBigTablekebutuhan untuk memiliki strategi pengindeksan yang berbeda dari apa yang Anda gunakan untuk sebagian besar tabel.

  • Tanpa Indeks Clustered data Anda akan disimpan sebagai tumpukan dengan Row Identifier (RID) yang sama sekali bukan mekanisme pencarian yang baik. Tetapi, seperti yang disebutkan sebelumnya, Anda dapat membuat indeks yang unik dan tidak unik untuk menangani pertanyaan Anda.

Yang sekarang membuat Anda mempertimbangkan Heaps:

Tumpukan dan Indeks: https://msdn.microsoft.com/en-us/library/hh213609.aspx

  • Ketika sebuah tabel disimpan sebagai tumpukan, setiap baris diidentifikasi dengan merujuk ke pengidentifikasi baris (RID) yang terdiri dari nomor file, nomor halaman data, dan slot pada halaman. Id baris adalah struktur kecil dan efisien. (Tapi itu bukan indeks .)
  • Kadang-kadang arsitek data menggunakan tumpukan ketika data selalu diakses melalui indeks nonclustered dan RID lebih kecil dari kunci indeks berkerumun .

Tetapi jika Anda juga memiliki beberapa 'hot spot' dalam kumpulan data besar, Anda juga dapat melihat jenis indeks lain:

Indeks yang Difilter: https://msdn.microsoft.com/en-us/library/cc280372.aspx

  • Indeks berfilter yang dirancang dengan baik meningkatkan kinerja kueri dan kualitas rencana eksekusi karena lebih kecil dari indeks tabel tidak tercakup penuh dan telah memfilter statistik. Statistik yang difilter lebih akurat daripada statistik tabel penuh karena hanya mencakup baris dalam indeks yang difilter .

  • Indeks yang difilter memiliki sejumlah batasan yang diuraikan dalam tautan ke indeks yang difilter.

Namun, jika Anda tertarik untuk memikirkan kemungkinan melewatkan Kunci Utama dan Indeks Berkelompok secara keseluruhan, Anda dapat membaca pos Markus Winand yang ditautkan di bawah ini. Dia mendemonstrasikan alasannya, dengan beberapa contoh kode, untuk menyarankan bahwa mungkin merupakan ide yang bagus untuk tidak menggunakan fitur-fitur tersebut.

http://use-the-index-luke.com/blog/2014-01/unreasonable-defaults-primary-key-clustering-key

Namun semuanya akhirnya kembali untuk memahami aplikasi Anda dan mendesain kode, tabel, indeks, dan sebagainya agar sesuai dengan pekerjaan yang Anda lakukan.

RLF
sumber
Untuk apa nilainya, dalam pekerjaan sehari-hari saya jika saya menemukan tabel yang merupakan tumpukan saya menganggapnya kemungkinan besar merupakan kesalahan dan memeriksa dengan pengembang untuk melihat apakah itu dibuat tumpukan sengaja.
RLF
-2

Beberapa hal yang perlu dipertimbangkan.

Sementara indeks (berkerumun atau tidak) pada nilai yang meningkat secara monoton menghemat halaman Anda terbelah selama sisipan massa, itu menciptakan titik panas baru di ujung akhir indeks. Meskipun ini mungkin bukan masalah dengan penyisipan utas tunggal, ia pasti akan meningkatkan pertikaian untuk aplikasi multithreaded yang memasukkan tupel baru dengan kecepatan tinggi, karena utas akan terus-menerus bersaing untuk mendapatkan akses ke halaman terakhir indeks.

Mengelompokkan tabel berdasarkan pengganti (identitas) PK jarang bermanfaat. Kunci primer semacam itu sebagian besar digunakan untuk mengakses tupel individual, satu per satu, atau memindai seluruh indeks untuk bergabung. Dalam kedua kasus itu tidak masalah apakah indeks berkerumun atau tidak (dengan pengecualian gabungan bergabung, mungkin, tetapi seberapa sering mereka?)

Saya pikir Anda akan mendapat manfaat paling banyak dari indeks berkerumun yang mencakup kueri yang meminta pemindaian rentang kunci dan predikat tambahan yang merujuk kolom lain.

mustaccio
sumber
Seberapa tinggi nilai yang harus dikeluarkan untuk ini agar benar-benar menjadi masalah?
ypercubeᵀᴹ
@ ypercube, bisakah saya mengatakan "itu tergantung"? Karena itu benar. Dengan tidak adanya pemicu di atas meja, saya berharap untuk mulai mengalami pertikaian dengan selusin utas dengan total 1K sisipan per detik.
mustaccio
Saya tidak setuju tetapi saya bertanya seberapa jauh seseorang bisa pergi dengan satu hot spot. Saya ingat pernah melihat artikel tentang menyisipkan baris 30K per detik dalam sebuah tabel dengan IDENTITAS sebagai CI (jika ingatan saya baik), tetapi saya tidak dapat menemukan posting blog.
ypercubeᵀᴹ
Diskusi ini tidak ada gunanya karena tidak ada beban kerja nyata yang berjalan melawan skema beton pada perangkat keras tertentu. Saya harap kita semua bisa setuju bahwa indeks pada urutan yang meningkat secara monoton akan menciptakan "hot spot"; apakah itu akan menciptakan hambatan yang tidak dapat diterima dan apakah seseorang harus peduli atau tidak tergantung pada keadaan.
mustaccio