Pertanyaan yang sangat bagus karena merupakan konsep yang sangat penting. Ini adalah topik besar dan apa yang akan saya tunjukkan kepada Anda adalah penyederhanaan sehingga Anda dapat memahami konsep dasarnya.
Pertama ketika Anda melihat tabel think index berkerumun . Dalam SQL server jika tabel tidak berisi indeks berkerumun itu adalah tumpukan. Membuat indeks berkerumun di atas meja sebenarnya mengubah tabel menjadi struktur tipe b-tree. Indeks berkerumun Anda adalah tabel Anda tidak terpisah dari tabel
Pernah bertanya-tanya mengapa Anda hanya dapat memiliki satu indeks berkerumun? Nah jika kita memiliki dua indeks berkerumun kita akan membutuhkan dua salinan tabel. Bagaimanapun juga, ini berisi data.
Saya akan mencoba dan menjelaskan ini dengan menggunakan contoh sederhana.
CATATAN: Saya membuat tabel dalam contoh ini dan mengisinya dengan lebih dari 3 juta entri acak. Kemudian jalankan pertanyaan aktual dan tempelkan rencana eksekusi di sini.
Apa yang benar-benar perlu Anda pahami adalah notasi O atau efisiensi operasional . Mari kita asumsikan Anda memiliki tabel berikut.
CREATE TABLE [dbo].[Customer](
[CustomerID] [int] IDENTITY(1,1) NOT NULL,
[CustomerName] [varchar](100) NOT NULL,
[CustomerSurname] [varchar](100) NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED
(
[CustomerID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF
, IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON
, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Jadi di sini kita memiliki tabel dasar dengan kunci berkerumun di CustomerID (Kunci primer dikelompokkan secara default). Dengan demikian tabel disusun / dipesan berdasarkan pada primaryID kunci Pelanggan. Level menengah akan berisi nilai-nilai CustomerID. Halaman data akan berisi seluruh baris sehingga merupakan baris tabel.
Kami juga akan membuat indeks non-cluster di bidang CustomerName. Kode berikut akan melakukannya.
CREATE NONCLUSTERED INDEX [ix_Customer_CustomerName] ON [dbo].[Customer]
(
[CustomerName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF
, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF
, DROP_EXISTING = OFF, ONLINE = OFF
, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Jadi dalam indeks ini Anda akan menemukan pada halaman data / tingkat daun node pointer ke tingkat menengah dalam indeks berkerumun. Indeks diatur / dipesan di sekitar bidang Nama Pelanggan. Dengan demikian tingkat menengah berisi nilai-nilai CustomerName dan tingkat daun akan berisi pointer (nilai-nilai pointer ini sebenarnya adalah nilai-nilai kunci utama atau kolom CustomerID).
Benar jadi jika kita menjalankan kueri berikut:
SELECT * FROM Customer WHERE CustomerID = 1
SQL mungkin akan membaca indeks berkerumun melalui operasi pencarian. Operasi pencarian adalah pencarian biner yang jauh lebih efisien daripada scan yang merupakan pencarian berurutan. Jadi dalam contoh kami di atas indeks dibaca dan dengan menggunakan pencarian biner, SQL dapat menghilangkan data yang tidak sesuai dengan kriteria yang kami cari. Lihat tangkapan layar terlampir untuk paket kueri.
Jadi jumlah operasi atau O Notasi untuk operasi pencarian adalah sebagai berikut:
- Lakukan pencarian biner pada indeks berkerumun dengan membandingkan nilai yang dicari dengan nilai-nilai di tingkat menengah.
- Mengembalikan nilai yang cocok (ingat karena indeks berkerumun memiliki semua data di dalamnya dapat mengembalikan semua kolom dari indeks karena itu adalah data baris)
Jadi ini adalah dua operasi. Namun jika kami menjalankan kueri berikut:
SELECT * FROM Customer WHERE CustomerName ='John'
SQL sekarang akan menggunakan indeks non-clustered di CustomerName untuk melakukan pencarian. Namun karena ini adalah indeks non-clustered itu tidak berisi semua data di baris.
Jadi SQL akan melakukan pencarian di tingkat menengah untuk menemukan catatan yang cocok kemudian melakukan pencarian menggunakan nilai yang dikembalikan untuk melakukan pencarian lain pada indeks berkerumun (alias tabel) untuk mengambil data aktual. Ini kedengarannya membingungkan, saya tahu tetapi membaca terus dan semuanya akan menjadi jelas.
Karena indeks non-cluster kami hanya berisi bidang CustomerName (nilai-nilai bidang yang diindeks disimpan dalam node perantara) dan penunjuk ke data yang merupakan CustomerID, indeks tidak memiliki catatan Nama Pelanggan. Nama Pelanggan harus diambil dari indeks atau tabel berkerumun.
Saat menjalankan kueri ini, saya mendapatkan paket eksekusi berikut:
Ada dua hal penting yang perlu Anda perhatikan pada screenshot di atas
- SQL mengatakan saya memiliki indeks yang hilang (teks berwarna hijau). SQL menyarankan saya membuat indeks pada CustomerName yang mencakup CustomerID dan CustomerSurname.
- Anda juga akan melihat bahwa 99% waktu kueri dihabiskan untuk melakukan pencarian kunci pada indeks kunci utama / indeks berkerumun.
Mengapa SQL menyarankan indeks pada CustomerName lagi? Yah karena indeks hanya berisi CustomerID dan SQL CustomerName masih harus menemukan Nama Pelanggan dari tabel / indeks berkerumun.
Jika kami membuat indeks dan kami menyertakan kolom Nama Pelanggan di indeks SQL akan dapat memenuhi seluruh permintaan dengan hanya membaca indeks non-clustered. Inilah sebabnya mengapa SQL menyarankan saya mengubah indeks non-clustered saya.
Di sini Anda dapat melihat operasi tambahan yang perlu dilakukan SQL untuk mendapatkan kolom Nama Pelanggan dari kunci berkerumun
Dengan demikian jumlah operasi adalah sebagai berikut:
- Lakukan pencarian biner pada indeks non-clustered dengan membandingkan nilai yang dicari dengan nilai-nilai di tingkat menengah
- Untuk node yang cocok baca node level daun yang akan berisi pointer untuk data dalam indeks berkerumun (node level daun akan berisi nilai kunci primer dengan cara).
- Untuk setiap nilai yang dikembalikan, lakukan baca pada indeks berkerumun (tabel) untuk mendapatkan nilai baris di sini kita akan membaca Nama Pelanggan.
- Kembalikan baris yang cocok
Itu adalah 4 operasi untuk mendapatkan nilai keluar. Dua kali jumlah operasi yang dibutuhkan dibandingkan dengan membaca indeks berkerumun. Menunjukkan kepada Anda bahwa indeks berkerumun Anda adalah indeks yang paling kuat karena berisi semua data.
Jadi hanya untuk memperjelas satu poin terakhir. Mengapa saya mengatakan bahwa pointer dalam indeks non-cluster adalah nilai kunci primer? Nah untuk menunjukkan bahwa node tingkat daun dari indeks non-clustered berisi nilai kunci primer saya mengubah permintaan saya ke:
SELECT CustomerID
FROM Customer
WHERE CustomerName='Jane'
Dalam kueri ini SQL dapat membaca CustomerID dari indeks non-clustered. Tidak perlu melakukan pencarian pada indeks berkerumun. Ini bisa Anda lihat dari rencana eksekusi yang terlihat seperti ini.
Perhatikan perbedaan antara permintaan ini dan permintaan sebelumnya. Tidak ada pencarian. SQL dapat menemukan semua data dalam indeks non-cluster
Mudah-mudahan Anda dapat mulai memahami bahwa indeks berkerumun adalah tabel dan indeks non-berkerumun JANGAN berisi semua data. Pengindeksan akan mempercepat pemilihan karena fakta bahwa pencarian biner dapat dilakukan tetapi hanya indeks berkerumun yang berisi semua data. Jadi pencarian pada indeks non-cluster hampir selalu menghasilkan nilai-nilai yang diambil dari indeks cluster. Operasi tambahan ini membuat indeks non-cluster kurang efisien daripada indeks cluster.
Semoga ini jelas. Jika ada yang tidak masuk akal silakan kirim komentar dan saya akan mencoba menjelaskan. Agak terlambat di sini dan otak saya merasa agak datar. Saatnya banteng merah.