Buat kembali Indeks Kunci Utama Sangat Besar

13

Saya memiliki database SQL yang di-host di Azure. Masalahnya adalah bahwa ukuran semakin di luar kendali, saya bisa melihat hingga 99% fragmentasi dalam indeks cluster Primary Key.

Saya dapat membangun kembali semua indeks lain dengan online=onopsi dan itu tidak akan mempengaruhi kinerja. Ukuran salah satu indeks PK Clustered lebih besar dari 200GB, dan untuk yang satu ini REBUILD...WITH (ONLINE=ON)menyebabkan penguncian.

Kami memang memiliki pengguna dari semua zona waktu yang mengakses situs jadi sungguh, saya tidak dapat menemukan waktu di mana saya dapat membangun kembali indeks secara offline.

Apa strategi terbaik untuk membangun kembali indeks besar tanpa downtime di situs?

Saya percaya reorganisasi tidak akan membantu karena fragmentasi adalah 99%. Masalahnya adalah bahwa tabel terkunci bahkan dengan online. Masalah utama adalah bahwa indeks lebih besar dari 200GB. Kunci utama adalah bilangan bulat.

Techy
sumber
4
@Techy, bahkan dengan fragmentasi tinggi, REORGANIZEakan mengurangi fragmentasi halaman daun dan ruang yang kompak REBUILD, hanya kurang efisien. Apakah Anda yakin ukuran besar disebabkan oleh fragmentasi? Apa faktor isi?
Dan Guzman
Apakah Anda tahu apa yang menyebabkan fragmentasi? Seberapa cepat Anda membangun kembali setelah Anda membangun kembali di alun-alun 1? Bisakah Anda memposting lebih banyak info tentang meja Anda?
pacreely
2
@Techy Saya telah mengedit pertanyaan untuk menambahkan beberapa info tambahan berdasarkan komentar Anda. Akan sangat membantu jika Anda juga memasukkan definisi tabel dalam pertanyaan, dan detail tambahan yang terkait dengan "tabel dikunci bahkan ketika [membangun kembali] online." Apa jenis menunggu yang Anda lihat?
AMtwo

Jawaban:

9

Meskipun agak terlambat, saya akan menjawab dengan harapan dapat membantu atau setidaknya menolak beberapa ide / komentar tambahan tentang masalah ini karena saya pikir ini adalah pertanyaan yang bagus.

Pertama, dan saya tidak tahu apakah Anda melakukan ini atau tidak, tapi tolong jangan berasumsi bahwa tingkat fragmentasi yang tinggi pada indeks selalu akan menyebabkan kinerja yang buruk. Statistik basi (misalnya sys.dm_db_stats_properties ) dan jumlah ruang putih yang tinggi per halaman (mis. Kolom avg_page_space_used_in_percent di sys.dm_db_index_physical_stats dmv ) memiliki lebih banyak relevansi terkait masalah kinerja daripada fragmentasi saja. Ya, indeks yang sangat terfragmentasi akan menghasilkan lebih banyak baca-depan dan Anda biasanya melihat statistik basi dan tingkat ruang putih yang lebih tinggi per halaman ditambah dengan fragmentasi, tetapi fragmentasi tidak secara langsung terkait dengan optimasi rencana kueri atau berapa banyak memori yang memuat indeks dari disk akan benar-benar mengkonsumsi. Paket kueri dipengaruhi oleh statistik dan jejak memori Anda membengkak dengan lebih banyak ruang putih . Misalnya, indeks yang 99% terfragmentasi tetapi memiliki kurang dari 5% rata-rata. white space dan statistik terkini kemungkinan tidak menyebabkan Anda mengalami masalah kinerja drastis dibandingkan dengan rencana eksekusi yang buruk sebagai akibat dari statistik basi atau paging indeks yang konstan yang terlalu besar untuk sepenuhnya tidak dapat ditampung dalam memori karena ada jumlah yang signifikan ruang putih hadir per halaman.

Jika fragmentasi benar-benar merupakan masalah , Anda dapat menguranginya, ONLINE, dengan mengeluarkan ALTER INDEX ... REORGANIZEpernyataan yang diidentifikasi oleh Dan Guzman dalam komentar. Ini tidak akan membuat indeks yang disederhanakan seperti REBUILDoperasi, tetapi akan mengurangi fragmentasi Anda. Kuncinya di sini adalah untuk mengidentifikasi windows dari penggunaan yang lebih rendah pada database Anda dan jalankan kemudian. Ini bisa 15 menit atau beberapa jam, jelas semakin lama semakin baik, tetapi kuncinya di sini adalah operasi ini tidak mundur dan mempertahankan kemajuan yang dibuat bahkan jika Anda membunuhnya di tengah eksekusi.

Jika, di dunia yang sempurna di mana fragmentasi Anda dihilangkan, apakah lebih masuk akal untuk menggunakan partisi pada tabel ini? Azure SQL Database memungkinkan partisi tabel dan Microsoft memiliki artikel bagus yang menguraikan beberapa strategi Partisi untuk Azure SQL Database . Jika data Anda non-volitile, mempartisi mungkin membantu mengurangi kebutuhan perawatan, dan jika digabungkan dengan Table Compression , Anda bahkan mungkin dapat mengurangi jejak penyimpanan keseluruhan. Jawaban awal Alberto Murillo menyinggung untuk memanfaatkan Horizontal Partitioning berdasarkan wilayah data, dan pendekatan ini dapat membantu membuat beberapa jendela pemeliharaan untuk Anda karena data Anda akan lebih spesifik secara regional daripada global.

Transisi ke tabel yang dipartisi tidak akan mudah dengan tidak adanya jendela pemeliharaan saat ini, tetapi Anda mungkin dapat menggunakan pendekatan yang diuraikan oleh Maria Zakourdaev yang menggunakan Tampilan yang Dipartisi dari atas tabel Anda saat ini dan tabel yang dipartisi baru untuk mulai mempartisi data masa depan. Seiring berjalannya waktu (dan mudah-mudahan data lama Anda dihapus), Anda akhirnya dapat beralih sepenuhnya ke tabel dipartisi. Sekali lagi, saya tidak tahu data atau aplikasi Anda, tetapi mungkin pendekatan ini adalah sesuatu yang dapat Anda terapkan.

John Eisbrener
sumber
4

Pertama, penting untuk mempertimbangkan apakah fragmentasi itu penting.

Jika permintaan Anda hanya melakukan pencarian baris tunggal, Anda mungkin tidak melihat fragmentasi sama sekali. Pada SAN modern, caching level SAN dapat membuat IO phyiscal cukup cepat sehingga fragmentasi tidak penting. Pada SSD, pola IO acak yang disebabkan oleh pemindaian indeks terfragmentasi sebenarnya dapat menghasilkan kinerja yang lebih baik daripada data yang tidak terfragmentasi.

Sering kali, orang-orang memperhatikan bahwa rebuiliding indeks memperbaiki masalah kinerja. Membangun kembali indeks juga membangun statistik baru. Ini mungkin kasus yang memperbaiki sebenarnya adalah statistik baru, bukan membangun kembali indeks. UPDATE STATISTICS...WITH FULLSCANmungkin cara yang lebih murah, lebih cepat, dan tidak terlalu mengganggu untuk menyelesaikan masalah kinerja yang sama.

Jika Anda tidak mengalami masalah yang disebabkan oleh fragmentasi, maka Anda bisa menghabiskan waktu & upaya yang signifikan tanpa keuntungan yang sebenarnya.

Kedua, ada dua jenis fragmentasi:

  1. Fragmentasi fisik. Inilah yang kebanyakan orang pikirkan ketika mereka berpikir tentang fragmentasi. Halaman rusak, dan perlu dipesan ulang. Saat memindai indeks, jenis fragmentasi ini terkadang bisa menjadi masalah. Saya biasanya memperhatikan ini memiliki dampak terbesar pada kinerja dengan pembacaan fisik . Jika Anda melihat hasil dari sys.dm_db_index_physical_stats, angka ini adalah avg_fragmentation_in_percentkolom.

  2. Fragmentasi kepadatan rendah. Fragmentasi ini disebabkan oleh halaman yang hanya diisi sebagian dengan data. Anda memiliki kepadatan data yang rendah karena data Anda tersebar di lebih dari halaman yang diperlukan. Akibatnya, membaca data memerlukan lebih banyak IO karena data tersebar di lebih banyak halaman daripada yang diperlukan. Ini dapat mempengaruhi bacaan logis dan fisik. Jika Anda melihat hasil dari sys.dm_db_index_physical_stats, angka ini adalah avg_page_space_used_in_percentkolom. Kolom ini hanya diisi ketika menggunakan SAMPLEDatau DETAILEDmode.

Jadi apa yang Anda lakukan tentang itu:

Fragmentasi Fisik : Jika Anda hanya mengejar angka tinggi avg_fragmentation_in_percent, benar-benar mempertimbangkan jika Anda membuang-buang waktu. Pastikan Anda memiliki kueri aktual yang berkinerja buruk, dan gunakan lingkungan pengujian untuk mengonfirmasi bahwa Anda memperbaiki masalah dengan menghilangkan fragmentasi.

Anda dapat mengatasi fragmentasi fisik dengan melakukan ALTER INDEX...REORGANIZE. The REORGANIZEoperasi online, bergerak halaman satu per satu untuk membenahi mereka kembali ke tatanan fisik. Jika Anda membunuh sebagian REORGANIZEpernyataan melalui jalan, pekerjaan apa pun yang sudah dilakukan dipertahankan - hanya satu halaman saat ini sedang dipindahkan akan dibatalkan. Melakukan REORGANIZEpada tabel besar yang sangat terfragmentasi dapat memerlukan lebih banyak ruang log transaksi total, dan dalam mode pemulihan penuh dapat menghasilkan sejumlah besar cadangan log transaksi. Mungkin juga membutuhkan waktu lebih lama untuk REORGANIZEindeks yang sangat terfragmentasi daripada untuk REBUILDitu.

Anda akan sering melihat saran untuk melakukan REBUILDpada indeks yang sangat terfragmentasi, daripada a REORGANIZE- Ini karena membangun kembali dari awal dapat lebih efisien. Namun, reorganisasi dapat menjadi operasi "lebih online" dan kadang-kadang lebih disukai, bahkan untuk indeks yang sangat terfragmentasi.

Fragmentasi kepadatan rendah tidak dapat diperbaiki oleh REORGANIZE. Itu hanya dapat diperbaiki dengan melakukan ALTER INDEX...REBUILD. Dengan melakukan indeks dengan ONLINE=ON, Anda harus dapat meminimalkan pemblokiran. Namun, REBUILDmasih perlu mengambil kunci sejenak untuk menukar indeks lama dengan indeks baru. Pada sistem yang sangat sibuk, mendapatkan kunci eksklusif ini terkadang bisa menjadi masalah. Anda harus dapat mengonfirmasi jika Anda mengalami masalah ini dengan menggunakan sesuatu seperti sp_whoisactive untuk memeriksa pemblokiran selama Anda membangun kembali, dan melihat detail kunci & menunggu. Menggunakan WAIT_AT_LOW_PRIORITYopsi ini mungkin berguna jika Anda tahu bahwa ada periode pemanfaatan rendah yang akan datang, dan pembangunan kembali Anda dapat "menyelinap" untuk swap ini ketika aktivitas turun cukup rendah untuk mencapai kunci itu. Perhatikan bahwa jangka panjangREBUILDOperasi juga akan menjadi transaksi terbuka yang sudah berjalan lama. Transaksi terbuka jangka panjang dapat memiliki masalah sendiri, terkait dengan penggunaan / penggunaan kembali log transaksi. Jika Anda menggunakan mirroring atau Grup Ketersediaan, ada juga pertimbangan untuk transaksi log mengulang pada replika sekunder.

AMtwo
sumber
Fragmentasi densitas rendah (alias "fragmentasi internal") sering diperbaiki oleh a REORGANIZE. Dari BOL : "Mengatur ulang juga meringkas halaman indeks." Nah, selama FILLFACTOR indeks sekarang akan memungkinkan kepadatan yang Anda cari.
Granger
2

Memperhatikan

Setelah komentar ini:

Anda akan kehilangan baris yang dimasukkan saat salin. Jika Anda ingin mencegah hal ini dengan mengunci tabel maka Anda berakhir dengan masalah yang sama seperti yang dinyatakan OP dalam pertanyaannya. Juga 200Gb tidak akan datang gratis :-) - Marco Sep 5 '17 jam 11:18

... Saya melihat bagaimana pendekatan ini tidak akan berhasil.

Saya akan meninggalkan jawaban ini sebagai contoh apa yang tidak boleh dilakukan.


Jika Anda memiliki cadangan 200+ GB gratis di Azure DB Anda, Anda bisa licik dengan "membangun kembali", dengan menyalin data Anda ke tabel yang sama sekali baru dan memesannya di sana.

Mencoba:

  • skrip Anda LiveTablemenjadi kosongNewTable
  • menyalin LiveTableke dalamNewTable
  • mengganti nama LiveTablemenjadiOldTable
  • mengganti nama NewTablemenjadiLiveTable

Jelas, gunakan nama tabel Anda , bukan LiveTable.

Oreo
sumber
Oreo, saya akan menggunakan pendekatan yang sama seperti Anda. Bahkan ketika ada baris yang disisipkan selama penyalinan, Anda masih dapat menambahkannya setelah NewTable diubah namanya menjadi LiveTable. Masalah utama yang Anda hindari di sini adalah waktu henti yang diperpanjang. Anda bahkan bisa bcp (i / o salin ke). Ini bukan ide yang buruk jadi saya juga tidak mengerti downvote :-)
Koen D
1

Idealnya, jika indeks dirancang dengan baik, kita tidak perlu bermain-main dengan mekanisme penguncian.

Bagi saya sepertinya Anda harus menerima penguncian untuk defrag indeks berkerumun. Jika ada peluang bagus untuk ini terjadi lagi, maka lihat mendesain ulang indeks berkerumun (itu harus sempit, unik, statis dan terus meningkat).

Saya tidak yakin versi SQL Server apa yang Anda gunakan, tetapi Anda bisa mencoba yang berikut pada 2012:

  • SET DEADLOCK_PRIORITY LOW - Ini memberitahu mesin bahwa indeks yang dibangun kembali harus menjadi korban kebuntuan ketika / jika ada.

  • MaxDOP = 1 - Nilai MaxDOP membatasi jumlah total CPU logis yang digunakan secara paralel untuk membuat indeks (2005 ke atas - edisi Enterprise saja).

Anda juga dapat mengubah konfigurasi kunci halaman / baris, tetapi saya tidak akan melakukannya tanpa pengujian. Anda bisa memperburuk penguncian, terutama jika indeksnya dirancang dengan buruk.

Pada tahun 2014 dan seterusnya, ada opsi berikut yang pada dasarnya memberitahu mesin untuk memungkinkan sesi lain untuk melanjutkan dan operasi indeks online untuk menunggu:

(WAIT_AT_LOW_PRIORITY (MAX_DURATION = 1 MINUTES, ABORT_AFTER_WAIT = SELF))
GPep
sumber
0

Saya telah menggunakan pendekatan yang sama seperti Oreo yang dijelaskan di atas dengan sukses besar! Satu-satunya hal yang hilang adalah Anda harus menjalankan skrip pembaruan setelah Anda menyalin data dan membuat penggantian nama terakhir.

Pembaruan akan terlihat seperti ini:

Insert from OldTable into LiveTable
  Where not exists (select From OldTable Where LiveTable.Key = OldTable.Key)

Jika Kunci adalah kolom Identitas, Anda perlu menggunakan pendekatan yang sedikit berbeda.

SBB
sumber
Seperti dicatat di bawah jawaban Oreo, metodenya tidak akan berfungsi jika ada data yang masih ditambahkan ke tabel asli, kecuali jika Anda mengunci tabel asli yang mengalahkan tujuan latihan
Tom V - coba topanswers.xyz
-2

Cobalah menggunakan sharding untuk mendistribusikan data basis data Anda secara geografis. Anda kemudian akan dapat mengidentifikasi jendela perawatan yang berbeda untuk setiap lokasi geografis, dan waktu untuk melakukan pemeliharaan akan lebih pendek. Ini juga akan meningkatkan kinerja. Anda dapat mempelajari lebih lanjut tentang artikel ini . Jangan menunggu database menjadi lebih besar.

Dengan basis data besar dan pengguna yang terhubung 24 x 7, Anda perlu menggunakan indeks mengatur ulang dan memperbarui hanya statistik yang perlu diperbarui (sp_updatestats) untuk meminimalkan waktu yang diperlukan untuk pemeliharaan dan dampaknya kepada pengguna.

Semoga ini membantu.

Alberto Morillo
sumber