
Foto oleh panumas nikhomkhai via Pexels
Index adalah struktur data tambahan yang membantu SQL Server menemukan baris tertentu tanpa harus membaca seluruh tabel, mirip seperti daftar isi pada buku. SQL Server menyediakan dua jenis index utama: clustered index dan non-clustered index, yang bekerja dengan cara fundamental berbeda.
Clustered index menentukan urutan fisik penyimpanan data di tabel itu sendiri, sehingga setiap tabel hanya boleh memiliki satu clustered index. Non-clustered index, sebaliknya, disimpan terpisah dari data tabel dan berisi salinan kolom yang di-index beserta pointer menuju baris aslinya, dan satu tabel boleh memiliki banyak non-clustered index.
Memahami perbedaan ini penting karena memilih kolom yang salah untuk clustered index bisa memengaruhi performa seluruh operasi pada tabel tersebut, bukan hanya query yang memakai index itu secara langsung.
Clustered Index Menentukan Urutan Fisik Data
Clustered index pada kolom PRIMARY KEY
Non-Clustered Index sebagai Struktur Terpisah
Non-clustered index disimpan terpisah dari tabel
Key Lookup Saat Index Tidak Mencakup Semua Kolom
Key Lookup terjadi saat kolom yang diminta tidak ada di index
Memilih Kolom yang Tepat untuk Clustered Index
Kolom sequential lebih ideal untuk clustered index
Dampak Fragmentasi Index terhadap Clustered dan Non-Clustered Index
Memeriksa dan memperbaiki fragmentasi index dengan REBUILD/REORGANIZE
Clustered index menyimpan data tabel itu sendiri terurut berdasarkan kolom key-nya, sehingga ketika baris baru disisipkan di tengah urutan logis (misalnya pada kolom yang bukan selalu bertambah seperti GUID acak), SQL Server harus melakukan page split yang memecah satu halaman data menjadi dua agar baris baru muat, dan proses inilah penyebab utama fragmentasi pada clustered index.
Non-clustered index mengalami mekanisme fragmentasi yang serupa karena strukturnya juga berupa B-tree terpisah yang menyimpan kolom key beserta pointer ke baris data, sehingga pola insert dan update yang acak pada kolom yang di-index akan memicu page split yang sama, meskipun dampaknya terhadap ukuran index non-clustered biasanya lebih kecil dibanding pada clustered index yang memuat seluruh kolom tabel.
Fragmentasi yang tinggi membuat SQL Server harus membaca lebih banyak halaman fisik dari disk untuk jumlah data logis yang sama, karena halaman-halaman tersebut tidak lagi berurutan dan terisi tidak penuh akibat page split; pemeliharaan rutin dengan REORGANIZE untuk fragmentasi ringan atau REBUILD untuk fragmentasi berat membantu menyusun ulang struktur fisik index agar pembacaan sekuensial kembali efisien.
Filtered Index untuk Subset Data yang Sering Diakses
Filtered index hanya menyimpan baris yang memenuhi kondisi WHERE tertentu
Filtered index adalah non-clustered index yang didefinisikan dengan klausa WHERE, sehingga hanya baris yang memenuhi kondisi tersebut yang dimasukkan ke dalam struktur index, berbeda dari index biasa yang selalu mencakup seluruh baris tabel. Pendekatan ini sangat berguna ketika query yang sering dijalankan hanya peduli pada subset kecil dari keseluruhan data, misalnya hanya order dengan status 'Pending' dari jutaan total baris order.
Karena ukurannya yang jauh lebih kecil dibanding index penuh pada kolom yang sama, filtered index membutuhkan lebih sedikit ruang penyimpanan dan lebih sedikit biaya pemeliharaan saat INSERT atau UPDATE, sebab hanya baris yang memenuhi kondisi filter yang memicu pembaruan index tersebut. Statistik yang dikumpulkan untuk filtered index juga lebih akurat untuk subset datanya dibanding statistik pada index penuh yang mencerminkan keseluruhan distribusi data.
Kondisi WHERE pada filtered index harus cocok atau menjadi subset dari kondisi WHERE pada query agar optimizer mau memakainya, dan kondisi tersebut hanya boleh memakai operator perbandingan sederhana seperti =, <>, >, <, IS NULL, dan IS NOT NULL terhadap kolom yang tidak nullable secara kompleks, sehingga filtered index paling cocok untuk kasus seperti memisahkan baris aktif dari non-aktif, atau baris dengan nilai NULL dari yang tidak NULL pada kolom yang jarang diisi.
Index Intersection Saat Dua Index Sempit Digabung Optimizer
Optimizer menggabungkan hasil dua index sempit lewat index intersection
Index intersection terjadi ketika optimizer memutuskan memakai lebih dari satu non-clustered index yang masing-masing sempit untuk menjawab satu query, lalu menggabungkan baris hasil seek dari tiap index tersebut melalui operator join seperti Hash Match, dibanding hanya mengandalkan satu index dan melakukan filter tambahan di memori atau Key Lookup.
Pendekatan ini jarang dipilih optimizer dibanding satu composite index yang mencakup seluruh kolom filter, karena menggabungkan dua index tetap membutuhkan operasi join tambahan yang punya biaya tersendiri. Munculnya index intersection pada execution plan sering menjadi sinyal bahwa membuat satu composite index pada kombinasi kolom yang sama, misalnya (Status, CustomerID), kemungkinan akan menghasilkan rencana eksekusi yang lebih efisien dibanding dua index terpisah tersebut. Memeriksa tab properti pada operator join di execution plan membantu memastikan apakah index intersection benar-benar sedang terjadi, sebelum memutuskan untuk merancang ulang index yang ada.
Kesalahan Umum yang Sering Terjadi
Membuat Terlalu Banyak Non-Clustered Index
Setiap non-clustered index menambah overhead saat INSERT, UPDATE, dan DELETE karena index tersebut juga harus diperbarui, sehingga tabel dengan terlalu banyak index justru bisa memperlambat operasi tulis secara signifikan.
Memilih Kolom yang Sering Berubah sebagai Clustered Index
Clustered index pada kolom yang nilainya sering di-update akan memaksa SQL Server memindahkan baris secara fisik setiap kali nilai berubah, berbeda dengan update pada kolom biasa yang tidak memengaruhi urutan fisik data.
Tidak Menyertakan Kolom yang Sering Diminta dalam Index
Non-clustered index yang tidak mencakup kolom yang sering diminta bersamaan (melalui INCLUDE) akan terus memicu Key Lookup yang mahal, padahal masalah ini bisa dihindari dengan sedikit penyesuaian definisi index.
Kapan Pendekatan Ini Tidak Cocok Dipakai
Clustered index memberikan performa terbaik untuk query yang mengambil data berdasarkan urutan atau range pada kolomnya, namun hanya bisa ada satu per tabel sehingga pemilihannya harus dipikirkan matang di awal desain.
Non-clustered index memberi fleksibilitas untuk mengoptimasi banyak pola query berbeda sekaligus, namun setiap index tambahan membawa biaya pemeliharaan saat data berubah, sehingga jumlahnya perlu diseimbangkan dengan frekuensi baca dibanding tulis pada tabel tersebut.
Ringkasan
Clustered index menentukan urutan fisik data dan hanya boleh satu per tabel, sementara non-clustered index adalah struktur tambahan terpisah yang bisa dibuat banyak untuk mendukung berbagai pola query. Pilih kolom clustered index yang stabil dan sequential, dan gunakan non-clustered index secukupnya sesuai pola akses data yang benar-benar sering dipakai aplikasi.
Seri Belajar SQL Server:
← Sebelumnya: Membaca Execution Plan untuk Optimasi Query
→ Selanjutnya: Covering Index dan Dampaknya pada Performa