Ketika tabel memiliki indeks berkerumun, indeks adalah data tabel (jika tidak, Anda memiliki tabel tipe tumpukan). Pembangunan kembali indeks berkerumun (sebenarnya indeks apa pun, tetapi ruang tidak akan dihitung sebagai "data" untuk indeks yang tidak berkerumun) akan menghasilkan halaman yang digunakan sebagian digabung menjadi bentuk yang lebih lengkap.
Saat Anda memasukkan data ke dalam indeks (berkerumun atau sebaliknya) di halaman daun urutan indeks dibuat sesuai kebutuhan dan Anda hanya akan memiliki satu halaman parsial: satu di bagian akhir. Saat Anda memasukkan data di luar urutan indeks, halaman perlu dipisah agar data tersebut pas di tempat yang tepat: Anda berakhir dengan dua halaman yang kira-kira setengah penuh dan baris baru masuk ke salah satunya. Seiring waktu, hal ini dapat terjadi banyak, menghabiskan cukup banyak ruang ekstra, meskipun pada tahap selanjutnya memasukkan akan mengisi beberapa celah. Halaman non-daun akan melihat efek yang sama juga, tetapi halaman data sebenarnya jauh lebih signifikan dalam ukuran daripada mereka.
Menghapus juga dapat menghasilkan sebagian halaman. Jika Anda menghapus semua baris dalam halaman itu akan dihitung sebagai "tidak digunakan" tetapi jika memiliki satu atau lebih baris data yang tersisa itu masih dihitung sebagai sedang digunakan. Bahkan jika hanya ada satu baris menggunakan 10 byte dalam satu halaman, halaman itu dihitung sebagai 8192 byte dalam hitungan ruang yang digunakan. Sekali lagi sisipan di masa depan mungkin mengisi beberapa celah.
Untuk baris panjang variabel, pembaruan juga dapat memiliki efek yang sama: karena satu baris semakin kecil itu dapat meninggalkan ruang di halamannya yang nantinya tidak mudah untuk digunakan kembali, dan jika sebuah baris di halaman yang hampir penuh tumbuh lebih lama, hal itu dapat memaksa pemisahan halaman .
SQL Server tidak menghabiskan waktu untuk menormalkan data dengan mengatur ulang bagaimana halaman digunakan, sampai secara eksplisit diberitahu seperti indeks Anda membangun kembali pesanan, karena latihan pengumpulan sampah seperti itu bisa menjadi mimpi buruk kinerja.
Saya menduga ini adalah apa yang Anda lihat, meskipun saya akan mengatakan bahwa memiliki cukup ruang yang dialokasikan untuk ~ 2,7 kali jumlah data yang benar-benar diperlukan adalah kasus yang sangat buruk. Mungkin menyiratkan bahwa Anda memiliki sesuatu yang acak sebagai salah satu kunci penting dalam indeks (mungkin kolom UUID) yang berarti bahwa baris baru tidak mungkin ditambahkan dalam urutan indeks, dan / atau bahwa sejumlah besar penghapusan telah terjadi baru-baru ini.
Contoh Pemisahan Halaman
Memasukkan dalam urutan indeks dengan baris panjang tetap yang empat pas ke halaman:
Start with one empty page:
[__|__|__|__]
Add the first item in index order:
[00|__|__|__]
Add the next three
[00|02|04|06]
Adding the next will result in a new page:
[00|02|04|06] [08|__|__|__]
And so on...
[00|02|04|06] [08|10|12|14] [16|18|__|__]
Sekarang untuk menambahkan baris di luar urutan indeks (inilah sebabnya saya menggunakan angka genap hanya di atas): Menambahkan 11
berarti memperpanjang halaman kedua itu (tidak mungkin karena ukurannya tetap), memindahkan semuanya di atas 11 ke atas (terlalu mahal untuk indeks besar) atau membelah halaman seperti:
[00|02|04|06] [08|10|11|__] [12|14|__|__] [16|18|__|__]
Dari sini, menambahkan 13
dan 17
tidak akan menghasilkan perpecahan karena saat ini ada ruang di halaman yang relevan:
[00|02|04|06] [08|10|11|__] [12|13|14|__] [16|17|18|__]
tetapi menambahkan 03 akan:
[00|02|03|__] [04|06|__|__] [08|10|11|__] [12|13|14|__] [16|17|18|__]
Seperti yang Anda lihat, setelah operasi penyisipan tersebut, kami saat ini memiliki 5 halaman data yang dialokasikan yang dapat memenuhi total 20 baris, tetapi kami hanya memiliki 14 baris di sana ("membuang-buang" 30% dari ruang).
Rekondisi dengan opsi default (lihat di bawah tentang "faktor pengisian") akan menghasilkan:
[00|02|03|04] [06|08|10|11] [12|13|14|16] [17|18|__|__]
menyimpan satu halaman dalam contoh sederhana ini. Sangat mudah untuk melihat bagaimana penghapusan dapat memiliki efek yang sama seperti sisipan out-of-index.
Mitigasi
Jika Anda mengharapkan data datang dalam urutan yang cukup acak sehubungan dengan urutan indeks, Anda dapat menggunakan FILLFACTOR
opsi saat membuat atau membangun kembali indeks untuk memberitahu SQL Server untuk secara artifisial membuat celah untuk mengisi - mengurangi pemisahan halaman dalam jangka panjang tetapi mengambil lebih banyak ruang pada awalnya. Tentu saja salah nilai ini bisa membuat segalanya jauh lebih buruk daripada membuat situasi lebih baik, jadi tangani dengan hati-hati.
Pemisahan halaman, terutama pada indeks berkerumun, dapat memiliki implikasi kinerja untuk menyisipkan / memperbarui sehingga FILLFACTOR
kadang-kadang di-tweak karena alasan itu alih-alih masalah penggunaan ruang dalam database yang melihat banyak aktivitas penulisan (tetapi untuk sebagian besar aplikasi, di mana bacaan lebih banyak daripada menulis dengan beberapa urutan besarnya, Anda biasanya lebih baik meninggalkan faktor pengisian sebesar 100% kecuali untuk kasus tertentu seperti di mana Anda memiliki indeks di atas kolom dengan konten acak yang efektif).
Saya berasumsi DB nama besar lainnya memiliki opsi yang serupa, jika Anda memerlukan level kontrol ini juga.
Memperbarui
Mengenai ALTER INDEX
pernyataan yang ditambahkan ke pertanyaan setelah saya mulai mengetik di atas: Saya berasumsi bahwa opsi yang sama seperti ketika indeks pertama kali dibangun (atau terakhir dibangun kembali) tetapi jika tidak maka opsi kompresi bisa sangat signifikan jika ditambahkan ini waktu sekitar. Juga dalam pernyataan itu fillfactor diatur ke 85% bukan 100% sehingga setiap halaman daun akan ~ 15% kosong segera setelah pembangunan kembali.