Pernyataan SQL Server sebentar-sebentar lambat pada SQL Server 2008 R2


13

Pada salah satu pelanggan kami, kami mengalami beberapa masalah kinerja pada aplikasi kami. Ini adalah aplikasi web .NET 3.5 yang mengkonsumsi dan memperbarui data pada database SQL Server. Saat ini lingkungan produksi kami terdiri dari mesin Windows 2008 R2 sebagai ujung depan, dan kluster SQL Server 2008 R2 di ujung belakang. Aplikasi kami menggunakan COM + dan MSDTC untuk terhubung ke database.

Inilah yang terjadi: pengguna akhir kami kadang mengeluh kelambatan dalam aplikasi. Beberapa halaman membutuhkan waktu lebih lama untuk memuat daripada yang diharapkan. Ketika mencoba mencari tahu apa yang terjadi, saya berhasil menemukan beberapa perilaku aneh di sisi database yang mungkin menjadi penyebab penurunan kinerja. Saya perhatikan bahwa kadang-kadang ada beberapa pernyataan SQL yang membutuhkan lebih banyak waktu untuk menjalankan apa yang diharapkan. Saya berhasil mengidentifikasi beberapa pernyataan ini (terutama pemanggilan beberapa prosedur tersimpan aplikasi kami) menggunakan jejak profiler (dengan templat TSQL_Duration) untuk mengidentifikasi kueri yang sudah berjalan lama.

Masalahnya adalah bahwa ketika saya menjalankan prosedur tersimpan ini secara langsung pada database di SQL Management Studio kadang-kadang mereka butuh waktu lama (sekitar 7/8 detik), di lain waktu mereka cepat (di bawah 1 detik). Saya tidak tahu mengapa ini terjadi dan itu membuat saya gila, karena mesin SQL (4 core, 32 GB) tidak digunakan oleh aplikasi lain, dan pertanyaan ini seharusnya tidak membutuhkan waktu lama untuk berjalan.

Tidak menjadi DBA atau guru SQL Server, saya sudah mencoba melihat beberapa hal yang dapat membantu saya memahami masalahnya. Inilah langkah-langkah yang telah saya ambil untuk mencoba menyelesaikan masalah dan apa yang saya temukan sejauh ini:

  • Semua kode TSQL yang dipanggil oleh aplikasi ditulis dalam prosedur tersimpan.
  • Saya mengidentifikasi beberapa permintaan yang berjalan lama pada profiler SQL Server, namun ketika saya menjalankan ini di Management Studio mereka butuh waktu lama untuk menjalankan (dari 4 hingga 10 detik), atau berjalan cepat (di bawah 1 detik). Saya menjalankan kueri yang sama persis dengan data yang sama yang dikirimkan dalam parameter. Pertanyaan ini terutama disimpan prosedur dengan pernyataan pilih di dalamnya
  • Saya mencoba melihat statistik menunggu dan antrian untuk mencoba dan mencari tahu apakah ada proses yang menunggu pada beberapa sumber daya. Saya menjalankan kueri berikut:

WITH Waits AS
    (SELECT
        wait_type,
        wait_time_ms / 1000.0 AS WaitS,
        (wait_time_ms - signal_wait_time_ms) / 1000.0 AS ResourceS,
        signal_wait_time_ms / 1000.0 AS SignalS,
        waiting_tasks_count AS WaitCount,
        100.0 * wait_time_ms / SUM (wait_time_ms) OVER() AS Percentage,
        ROW_NUMBER() OVER(ORDER BY wait_time_ms DESC) AS RowNum
    FROM sys.dm_os_wait_stats
    WHERE wait_type NOT IN (
        'CLR_SEMAPHORE', 'LAZYWRITER_SLEEP', 'RESOURCE_QUEUE', 'SLEEP_TASK',
        'SLEEP_SYSTEMTASK', 'SQLTRACE_BUFFER_FLUSH', 'WAITFOR', 'LOGMGR_QUEUE',
        'CHECKPOINT_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH', 'XE_TIMER_EVENT',  'BROKER_TO_FLUSH',
        'BROKER_TASK_STOP', 'CLR_MANUAL_EVENT', 'CLR_AUTO_EVENT',     'DISPATCHER_QUEUE_SEMAPHORE',
        'FT_IFTS_SCHEDULER_IDLE_WAIT', 'XE_DISPATCHER_WAIT', 'XE_DISPATCHER_JOIN', 'BROKER_EVENTHANDLER',
        'TRACEWRITE', 'FT_IFTSHC_MUTEX', 'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
        'BROKER_RECEIVE_WAITFOR', 'ONDEMAND_TASK_QUEUE', 'DBMIRROR_EVENTS_QUEUE',
        'DBMIRRORING_CMD', 'BROKER_TRANSMITTER', 'SQLTRACE_WAIT_ENTRIES',
        'SLEEP_BPOOL_FLUSH', 'SQLTRACE_LOCK')
    )
SELECT
    W1.wait_type AS WaitType, 
    CAST (W1.WaitS AS DECIMAL(14, 2)) AS Wait_S,
    CAST (W1.ResourceS AS DECIMAL(14, 2)) AS Resource_S,
    CAST (W1.SignalS AS DECIMAL(14, 2)) AS Signal_S,
    W1.WaitCount AS WaitCount,
    CAST (W1.Percentage AS DECIMAL(4, 2)) AS Percentage,
    CAST ((W1.WaitS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgWait_S,
    CAST ((W1.ResourceS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgRes_S,
    CAST ((W1.SignalS / W1.WaitCount) AS DECIMAL (14, 4)) AS AvgSig_S
FROM Waits AS W1
    INNER JOIN Waits AS W2 ON W2.RowNum <= W1.RowNum
GROUP BY W1.RowNum, W1.wait_type, W1.WaitS, W1.ResourceS, W1.SignalS, W1.WaitCount,    W1.Percentage
HAVING SUM (W2.Percentage) - W1.Percentage < 95; -- percentage threshold
GO

Inilah yang saya temukan:

  • Setelah saya mereset statistik menggunakan DBCC SQLPERF (sekitar 1 atau 2 jam setelah), jenis menunggu yang paling saya miliki adalah SOS_SCHEDULER_YIELD dan WRITELOG
  • Seiring waktu (setelah eksekusi sekitar 1 hari), jenis menunggu yang paling banyak terjadi pada basis data adalah CXPACKET (67%) dan OLEDB (17%), meskipun waktu tunggu rata-rata untuk masing-masing tidak lama. Saya juga memperhatikan bahwa pernyataan yang berjalan lebih lama yang diidentifikasi pada SQL Profiler adalah panggilan ke prosedur tersimpan yang mengembalikan lebih dari satu resultset (seringkali 3). Bisakah ada masalah paralellisme di sini? Apakah ada cara saya bisa mencoba mengidentifikasi apakah ini penyebab masalahnya?
  • Saya pernah membaca bahwa OLEDB menunggu dapat disebabkan oleh panggilan ke sumber daya OLEDB seperti server yang ditautkan. Kami memang memiliki server yang terhubung untuk terhubung dengan mesin Layanan Pengindeksan (MSIDXS), namun tidak satu pun dari pernyataan yang diidentifikasi sebagai berjalan lama menggunakan server tertaut itu.
  • Waktu tunggu rata-rata yang lebih tinggi yang saya miliki adalah untuk menunggu tipe LCK_M_X (rata-rata sekitar 1,5 detik), tetapi tipe menunggu ini tidak terlalu sering terjadi dibandingkan dengan tipe lain (misalnya, 64 LCK_M_X menunggu vs 10.823 menunggu CXPACKET pada periode waktu yang sama ).
  • Satu hal yang saya perhatikan adalah bahwa layanan MSDTC tidak berkerumun. Layanan SQL Server berkerumun tetapi tidak MSDTC. Bisakah ada hit kinerja karena ini? Kami menggunakan MSDTC karena aplikasi kami menggunakan Enterprise Services (DCOM) untuk mengakses database, tetapi server tidak diinstal dan dikonfigurasi oleh kami, tetapi oleh klien kami.

Adakah yang bisa membantu saya lebih memahami data ini? Adakah yang bisa membantu saya memahami apa yang mungkin terjadi? Apakah ada sesuatu yang bisa saya lakukan di server untuk mencoba dan mencari tahu? Haruskah saya berbicara dengan tim pengembangan aplikasi?

Jawaban:


4

Terima kasih atas penjelasan terperinci masalah Anda (sebenarnya salah satu pertanyaan terbaik yang diajukan).

WRITELOG adalah jenis penantian yang sangat umum, jadi jangan khawatir. Melihat SOS_SCHEDULER_YIELD menunjukkan tekanan CPU dan juga CXPACKET, ada kemungkinan bahwa harus ada beberapa indeks yang hilang dan Anda mungkin mengambil banyak data dari permintaan untuk sistem OLTP. Saya menyarankan Anda untuk melihat pada Missing Indexes DMV dan melihat apakah ada indeks (hampir pasti akan ada lebih dari beberapa) yang ada dalam procs yang dipertanyakan.

http://sqlfool.com/2009/04/a-look-at-missing-indexes/

http://troubleshootingsql.com/2009/12/30/how-to-find-out-the-missing-indexes-on-a-sql-server-2008-or-2005-instance-along-with-the- buat-indeks-perintah /

Cari posting Jonathan Kehayias di sqlblog.com tentang ini juga.

Juga, lihat sniffing Parameter.

http://sommarskog.se/query-plan-mysteries.html

http://pratchev.blogspot.com/2007/08/parameter-sniffing.html

Ini BUKAN jawaban yang bersaing untuk kebutuhan Anda tetapi titik awal yang baik. Beri tahu kami jika Anda membutuhkan detail lebih lanjut.


1

Kami memiliki masalah yang sama setelah salah satu karyawan menulis ulang beberapa prosedur yang tersimpan. Ternyata ada banyak percabangan dan Dynamic SQL sedang dibangun yang mengubah klausa mana secara signifikan.

Misalnya (tentu saja disederhanakan):

Jika Model adalah "X" di mana klausa mencari ProductCode sama dengan nilai-nilai tertentu.
Jika Model adalah "Y" klausa mana yang mencari ProductType sama dengan nilai-nilai tertentu.

SQL Server akan membangun rencana kueri berdasarkan parameter input saat pertama kali prosedur tersimpan dijalankan. Jadi, jika rencana kueri dibangun di atas logika yang menggunakan "ProductCode" sama dengan dan Anda meminta "ProductType" sama dengan itu adalah rencana kueri yang tidak cocok dan kemungkinan besar hasil dalam pemindaian tabel penuh.

Anda dapat mencoba menempatkan " DENGAN RECOMPILE " di bagian atas prosedur yang tersimpan. BUAT PROSEDUR (Transact-SQL)

Cara terbaik yang bisa saya uraikan adalah sebagai berikut:

Misalkan Anda memiliki daftar nama dan nomor telepon yang diurutkan berdasarkan Nama Belakang. Ini berfungsi baik untuk menemukan orang yang menggunakan Nama Belakang (rencana permintaan berdasarkan Nama Belakang). Sekarang anggaplah Anda membutuhkan semua nama dan nomor telepon dalam Kode Area 203. Jika daftar Anda diurutkan berdasarkan Nama Belakang, satu-satunya cara untuk mendapatkan daftar lengkap semua Kode Area 203 orang adalah mulai dari atas dan membaca secara berurutan melalui masing-masing dan setiap catatan. (Pemindaian Tabel Lengkap).


Menggunakan exec()fungsi akan menjelaskan perilaku yang diamati. Dalam hal ini menggunakan sp_executesqlbiasanya menyelesaikan masalah dengan pernyataan SQL dinamis.
ajeh

1

Jika kueri berjalan sesekali cepat dan lambat dalam SSMS dan aplikasi, Anda mungkin memiliki masalah statistik atau parameter sniffing.

Saya akan menjalankan prosedur yang tersimpan ini, kemudian meninjau rencana eksekusi untuk menarik properti dari operator root (simpul hijau di paling kiri dari setiap pernyataan).

Berapa taksiran jumlah baris dalam rencana eksekusi, dibandingkan berapa banyak baris aktual yang dikembalikan?

Apakah parameter yang dikompilasi cocok dengan parameter kueri yang sebenarnya?

Jika rencana eksekusi dibuat untuk parameter yang hanya mengembalikan beberapa baris, dan Anda menjalankan prosedur yang sama dengan parameter yang mengembalikan sejumlah besar baris, SQL dapat menggunakan rencana eksekusi yang salah untuk kueri.

Pilihan paket eksekusi terkait erat dengan statistik SQL, jadi sebaiknya Anda membangun kembali statistik Anda secara berkala.

Jika Anda memiliki prosedur tersimpan yang terkadang mengembalikan sejumlah kecil data atau data dalam jumlah besar tergantung pada parameter yang disediakan, Anda mungkin memiliki masalah mengendus parameter.

Jika membangun kembali statistik Anda tidak menyelesaikan masalah, Anda dapat menjalankan pernyataan paling mahal di dalam prosedur tersimpan OPTION (RECOMPILE)


0

Karena Anda telah mengidentifikasi kueri yang sudah berjalan lama, Anda dapat mengambil rencana eksekusi untuk prosedur ini dari cache Anda dan melihat apakah Anda dapat menentukan masalah di sana. Seringkali ada konversi tipe data implisit atau run-time. Juga, jika Anda membersihkan atau memasukkan banyak data, disarankan untuk memperbarui statistik juga.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.