Ketika kueri SQL yang sebelumnya cepat mulai berjalan lambat, di mana saya mencari sumber masalah?

37

Latar Belakang

Saya memiliki kueri yang berjalan terhadap SQL Server 2008 R2 yang bergabung dan / atau bergabung-kiri sekitar 12 "tabel" berbeda. Basis datanya cukup besar dengan banyak tabel lebih dari 50 juta baris dan sekitar 300 tabel berbeda. Ini untuk perusahaan besar yang memiliki 10 gudang di seluruh negeri. Semua gudang membaca dan menulis ke database. Jadi itu cukup besar dan sangat sibuk.

Kueri yang bermasalah dengan tampilannya adalah seperti ini:

select t1.something, t2.something, etc.
from Table1 t1
    inner join Table2 t2 on t1.id = t2.t1id
    left outer join (select * from table 3) t3 on t3.t1id = t1.t1id
    [etc]...
where t1.something = 123

Perhatikan bahwa salah satu gabungan adalah pada sub-kueri yang tidak berkorelasi.

Masalahnya adalah bahwa mulai pagi ini, tanpa perubahan apa pun (yang saya atau siapa pun di tim saya ketahui) ke sistem, permintaan yang biasanya memakan waktu sekitar 2 menit untuk berjalan, mulai mengambil satu setengah jam untuk berjalan - ketika itu berlari sama sekali. Sisa dari database bersenandung dengan baik. Saya telah mengeluarkan query ini dari sproc yang biasanya dijalankan dan saya menjalankannya dalam SSMS dengan variabel parameter hard-coded dengan kelambatan yang sama.

Anehnya adalah ketika saya mengambil sub-kueri yang tidak berkorelasi dan membuangnya ke tabel temp, dan kemudian menggunakannya sebagai pengganti sub-kueri, kueri berjalan dengan baik. Juga (dan ini yang paling aneh bagi saya) jika saya menambahkan potongan kode ini ke akhir kueri, kueri berjalan hebat:

and t.name like '%'

Saya telah menyimpulkan (mungkin salah) dari percobaan kecil ini bahwa alasan untuk perlambatan adalah karena bagaimana rencana eksekusi cached SQL diatur - ketika kueri sedikit berbeda, ia harus membuat rencana eksekusi baru.

Pertanyaan saya adalah ini: Ketika kueri yang digunakan untuk berlari cepat tiba-tiba mulai berjalan lambat di tengah malam dan tidak ada yang lain yang terpengaruh kecuali untuk permintaan yang satu ini, bagaimana cara saya memecahkan masalah dan bagaimana saya mencegahnya terjadi di masa depan ? Bagaimana saya tahu apa yang SQL lakukan secara internal untuk membuatnya sangat lambat (jika permintaan buruk berjalan, saya bisa mendapatkan rencana pelaksanaannya tetapi itu tidak akan berjalan - mungkin rencana eksekusi yang diharapkan akan memberi saya sesuatu?)? Jika masalah ini adalah dengan rencana eksekusi, bagaimana saya menjaga SQL dari berpikir bahwa rencana eksekusi yang benar-benar jelek adalah ide yang bagus?

Juga, ini bukan masalah dengan sniffing parameter. Saya telah melihat itu sebelumnya, dan ini bukan itu, karena bahkan ketika saya hard-code varaibles di SSMS, saya masih mendapatkan kinerja yang lambat.

Trevor
sumber
Bisakah Anda membagikan rencana permintaan (yang lambat) di sini: brentozar.com/pastetheplan
MJH

Jawaban:

32

Ketika kueri yang digunakan untuk berlari cepat tiba-tiba mulai berjalan lambat di tengah malam dan tidak ada yang terpengaruh kecuali untuk permintaan yang satu ini, bagaimana cara saya memecahkan masalah itu ...?

Anda bisa mulai dengan memeriksa apakah rencana eksekusi masih ada dalam cache. Periksa sys.dm_exec_query_stats, sys.dm_exec_procedure_statsdan sys.dm_exec_cached_plans. Jika rencana eksekusi yang buruk masih di-cache Anda dapat menganalisanya, dan Anda juga dapat memeriksa statistik eksekusi. Statistik pelaksanaan akan berisi informasi sebagai pembacaan logis, waktu CPU dan waktu eksekusi. Ini dapat memberikan indikasi kuat apa masalahnya (mis. Pemindaian besar vs. pemblokiran). Lihat Mengidentifikasi kueri masalah untuk penjelasan cara menafsirkan data.

Juga, ini bukan masalah dengan sniffing parameter. Saya telah melihat itu sebelumnya, dan ini bukan itu, karena bahkan ketika saya hard-code varaibles di SSMS, saya masih mendapatkan kinerja yang lambat.

Saya tidak yakin. Variabel hard-coding dalam SSMS tidak membuktikan bahwa rencana eksekusi buruk yang lalu tidak dikompilasi dengan input yang miring. Silakan baca Parameter Sniffing, Embedding, dan Opsi RECOMPILE untuk artikel yang sangat bagus tentang topik ini. Lambat dalam Aplikasi, Cepat dalam SSMS? Memahami Misteri Kinerja adalah referensi bagus lainnya.

Saya telah menyimpulkan (mungkin salah) dari percobaan kecil ini bahwa alasan untuk perlambatan adalah karena bagaimana rencana eksekusi cached SQL diatur - ketika kueri sedikit berbeda, ia harus membuat rencana eksekusi baru.

Ini dapat dengan mudah diuji. SET STATISTICS TIME ONakan menunjukkan kepada Anda waktu kompilasi vs. eksekusi. SQL Server: Penghitung kinerja statistik juga akan mengungkapkan apakah kompilasi adalah masalah (terus terang, saya rasa tidak mungkin).

Namun, ada hal serupa yang mungkin Anda tekan: gerbang hibah permintaan. Baca Memahami hibah memori server SQL untuk detailnya. Jika permintaan Anda meminta dana besar pada saat ini tidak ada memori yang tersedia, itu harus menunggu, dan semuanya akan terlihat sebagai 'eksekusi lambat' untuk aplikasi. Menganalisa statistik info tunggu akan mengungkapkan jika ini masalahnya.

Untuk diskusi yang lebih umum tentang apa yang diukur dan apa yang harus dicari, lihat Bagaimana menganalisis kinerja SQL Server

Remus Rusanu
sumber
7

Ini adalah kutukan menjalankan query kompleks di SQL Server. Untungnya, itu tidak sering terjadi.

Lihatlah rencana kueri untuk kueri (saat berjalan lambat). Saya menduga Anda akan menemukan loop bergabung bersarang terjadi satu kali atau lebih pada tabel tanpa indeks untuk bergabung. Ini benar-benar memperlambat segalanya. Untuk memajukan, cara untuk memperbaikinya adalah dengan sebuah petunjuk. Tambahkan yang berikut di akhir kueri:

OPTION (MERGE JOIN, HASH JOIN)

Ini umumnya memperbaiki masalah ini bagi saya di masa lalu.

Apa yang mungkin terjadi adalah bahwa perubahan halus ke tabel (atau ketersediaan ruang sementara) menyebabkan pengoptimalan SQL lebih memilih algoritma join yang lebih lambat. Ini bisa sangat halus dan cukup mendadak. Saat Anda membuat tabel sementara, pengoptimal memiliki lebih banyak informasi tentang tabel (seperti ukurannya), sehingga dapat menghasilkan rencana yang lebih baik.

Gordon Linoff
sumber
1
Rencana eksekusi memang menggunakan nested loop join. Namun, ketika saya menempatkan petunjuk seperti yang Anda sarankan, saya mendapatkan kesalahan ini: "Prosesor kueri tidak dapat menghasilkan rencana kueri karena petunjuk yang ditentukan dalam permintaan ini. Kirim ulang permintaan tanpa menentukan petunjuk apa pun dan tanpa menggunakan SET FORCEPLAN." Ketika saya menambahkan OPSI (LOOP BERGABUNG) tentu saja, itu akan membuat rencana eksekusi tetapi saya masih memiliki masalah dengan itu berjalan lambat. Sudahkah Anda mengalami masalah ini? Sepertinya ia pikir perlu untuk bergabung.
@ Trevor. . . Tidak, saya belum benar-benar melihat masalah ini. Mungkin kueri Anda melakukan beberapa non-equijoins (tidak menggunakan tanda sama dengan) dan pengoptimal harus menggunakan nested loop bergabung di sana.
Gordon Linoff
3

Biasanya ini adalah indeks yang hilang yang menyebabkan masalah seperti ini.

Apa yang biasanya saya lakukan adalah menjalankan kueri menggunakan SQL Management Studio dan mengaktifkan 'Sertakan Rencana Eksekusi Aktual (CTRL + M)' dan mencari tahu yang bergabung memiliki persentase terbesar.

Aplikasi tidak fokus pada bottleneck, tetapi Anda dapat menemukannya "dengan cepat" hanya melihat hasilnya.

contoh di sini: 48PercentForTop

Xavier
sumber
2
indeks tidak akan tiba-tiba "hilang", jadi sementara ini dapat meningkatkan kinerja itu tidak menjelaskan masalah
Fowl
3

Baru-baru ini saya mengalami masalah yang sama yang membawa saya ke halaman ini.

@MartinSmith melakukan sesuatu ketika dia merekomendasikan untuk memperbarui statistik Anda dan menjelaskan rencana. Saya ingin menambahkan bahwa Anda juga harus mencoba memastikan Anda melihat menjalankan pekerjaan / permintaan yang dapat membuat kunci dan dengan demikian memperlambat waktu respons.

Dalam kasus saya pelakunya adalah statistik tabel pengumpulan pekerjaan. Untuk beberapa alasan itu tidak lengkap di jendela yang seharusnya, dan terus berjalan ketika pengguna kembali. Saya menemukan proses, membunuhnya dan pertanyaan mulai merespons lagi.

Saya harap ini membantu orang lain

daffyjeje
sumber
0

Anda juga perlu memeriksa apakah ada cadangan server atau pekerjaan Pengindeksan \ pengindeksan berjalan ketika Anda melihat masalah kinerja di T-SQL \ Prosedur.

Amol Nimbalkar
sumber