PILIH TOP 1 dari tabel yang sangat besar pada kolom indeks sangat lambat, tetapi tidak dengan urutan terbalik ("desc")

17

Kami memiliki database besar, sekitar 1TB, menjalankan SQL Server 2014 di server yang kuat. Semuanya bekerja dengan baik selama beberapa tahun. Sekitar 2 minggu yang lalu, kami melakukan pemeliharaan penuh, yang meliputi: Instal semua pembaruan perangkat lunak; membangun kembali semua indeks dan file DB kompak. Namun, kami tidak berharap bahwa pada tahap tertentu penggunaan CPU DB meningkat lebih dari 100% menjadi 150% ketika beban sebenarnya sama.

Setelah banyak pemecahan masalah, kami mempersempitnya menjadi kueri yang sangat sederhana, tetapi kami tidak dapat menemukan solusinya. Permintaannya sangat sederhana:

select top 1 EventID from EventLog with (nolock) order by EventID

Itu selalu memakan waktu sekitar 1,5 detik! Namun, permintaan serupa dengan "desc" selalu membutuhkan sekitar 0 ms:

select top 1 EventID from EventLog with (nolock) order by EventID desc

PTable memiliki sekitar 500 juta baris; EventIDadalah kolom indeks clustered primer (dipesan ASC) dengan tipe data bigint (kolom Identity). Ada beberapa utas memasukkan data ke dalam tabel di atas (EventID lebih besar), dan ada 1 utas menghapus data dari bawah (EventID lebih kecil).

Dalam SMS, kami memverifikasi bahwa dua pertanyaan selalu menggunakan rencana eksekusi yang sama:

  • Pemindaian indeks berkelompok;

  • Diperkirakan dan nomor baris sebenarnya adalah 1;

  • Diperkirakan dan jumlah aktual eksekusi adalah 1;

  • Perkirakan biaya I / O adalah 8500 (Tampaknya tinggi)

  • Jika dijalankan secara berurutan, biaya Query adalah 50% sama untuk keduanya.

Saya memperbarui statistik indeks with fullscan, masalahnya masih ada; Saya membangun kembali indeks itu lagi, dan masalahnya tampaknya sudah hilang selama setengah hari, tetapi kembali.

Saya menyalakan statistik IO dengan:

set statistics io on

kemudian jalankan dua pertanyaan secara berurutan dan temukan info berikut:

(Untuk kueri pertama, yang lambat)

Tabel 'PTable'. Pindai hitungan 1, bacaan logis 407670, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.

(Untuk kueri kedua, yang cepat)

Tabel 'PTable'. Pindai hitungan 1, bacaan logis 4, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.

Perhatikan perbedaan besar dalam pembacaan logis. Indeks digunakan dalam kedua kasus.

Fragmentasi indeks dapat menjelaskan sedikit, tetapi saya percaya dampaknya sangat kecil; dan masalahnya tidak pernah terjadi sebelumnya. Bukti lain adalah jika saya menjalankan kueri seperti:

select * from EventLog with (nolock) where EventID=xxxx   

Bahkan jika saya menetapkan xxxx ke EventID terkecil di tabel, kueri selalu kilat.

Kami memeriksa dan tidak ada masalah penguncian / pemblokiran.

Catatan: Saya baru saja mencoba menyederhanakan masalah di atas. "PTable" sebenarnya "EventLog"; yang PIDadalah EventID.

Saya mendapatkan hasil pengujian yang sama tanpa NOLOCKpetunjuk.

Adakah yang bisa membantu?

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Paket eksekusi permintaan yang lebih rinci dalam XML sebagai berikut:

https://www.brentozar.com/pastetheplan/?id=SJ3eiVnob

https://www.brentozar.com/pastetheplan/?id=r1rOjVhoZ

Saya tidak berpikir itu penting untuk memberikan pernyataan membuat tabel. Ini adalah database lama dan telah berjalan dengan sangat baik untuk waktu yang lama hingga pemeliharaan. Kami telah melakukan banyak penelitian sendiri dan mempersempitnya ke info yang disediakan dalam pertanyaan saya.

Tabel dibuat secara normal dengan EventIDkolom sebagai kunci utama, yang merupakan identitykolom tipe bigint. Saat ini, saya kira masalahnya adalah dengan fragmentasi indeks. Tepat setelah indeks dibangun kembali, masalah tampaknya hilang selama setengah hari; tapi mengapa ia kembali begitu cepat ...?

TiffanyP
sumber

Jawaban:

18

Pemindaian Indeks Clustered menunjukkan 423.723 pembacaan logis untuk mengembalikan baris pertama, mengambil 1926 ms:

GILA

Tampaknya ini agak banyak untuk menemukan baris pertama dalam urutan indeks.

Kemungkinan tugas pembersihan hantu Anda berjalan jauh di belakang, atau telah berhenti. Anda harus memeriksa ghost_record_countindeks berkerumun di sys.dm_db_index_physical_statsdan memantau perubahan dari waktu ke waktu.

The memerintahkan pemindaian dari ujung indeks yang melihat aktivitas delete konstan memiliki untuk memindai lebih banyak sekali catatan hantu sebelum menemukan pertama 'hidup' baris untuk kembali. Ini menjelaskan bacaan ekstra logis. Pencarian turun pohon b ke nilai terendah dari indeks akan menemukan catatan hantu jauh lebih sedikit.

Faktor lain yang mempengaruhi kinerja adalah bahwa pemindaian itu sendiri menjadi bertanggung jawab untuk menghapus catatan hantu sebagaimana disebutkan dalam Inside the Storage Engine: Pembersihan hantu secara mendalam oleh Paul Randal.

Anda harus memeriksa bahwa jejak bendera 661 (nonaktifkan pembersihan hantu) tidak aktif.

Solusi

Jika proses pembersihan hantu telah berhenti sepenuhnya, solusi paling efektif biasanya untuk memulai kembali contoh SQL Server. Anda juga harus memastikan bahwa SQL Server menjalankan salah satu Pembaruan Kumulatif terbaru. Ada banyak bug pembersihan hantu selama bertahun-tahun.

Dalam kasus spesifik Anda:

Ternyata masalah itu disebabkan oleh database tes lain di server yang sama. Basis data pengujian dipulihkan dengan "kehilangan data", dan rusak. Anehnya, proses pembersihan hantu tampaknya terjebak dalam database itu. Setelah kami menghapus basis data yang rusak dari SMSS, masalahnya teratasi dengan sendirinya (butuh waktu lama dan mungkin menyebabkan DB terkunci untuk sementara waktu).

Paul White Reinstate Monica
sumber