TSQL: Temukan kueri yang menyebabkan terlalu banyak kompilasi SQL dan kompilasi ulang SQL secara terpisah

8

Saya ingin mencari tahu apa yang menyebabkan Kompilasi SQL yang tinggi (bukan kompilasi ulang) yang saya lihat di penghitung monitor kinerja.

Inilah pendapat saya: Jika saya melihat banyak kompilasi SQl, maka itu berarti bahwa kueri pada sistem kami tidak di-cache karena alasan berikut:

  • Banyak pertanyaan adhoc
  • Menjalankan kueri yang tidak disimpan oleh SQl misalnya:

    UPDATE table1 SET col1 = 'String lebih panjang dari 8000 karakter .....' WHERE key_column = int

  • Paket waktu habis dan dihapus dari cache karena: Cache kehabisan ruang atau rencana tidak digunakan cukup lama.

Satu-satunya hal yang mendekati menangkap sisipan cache di profiler adalah Stored Procedures-> SP: CacheInserts tetapi hanya terlihat setelah cache prosedur tersimpan.

Jadi saya mencoba yang berikut untuk mendapatkan pertanyaan adhoc:

SELECT [cp].[refcounts] -- when Refcounts becomes 0, plan is excluded from cache.
    , [cp].[usecounts] 
    , [cp].[objtype] 
    , st.[dbid] 
    , st.[objectid] 
    , st.[text] 
    , [qp].[query_plan] 
FROM sys.dm_exec_cached_plans cp     
CROSS APPLY sys.dm_exec_sql_text ( cp.plan_handle ) st     
CROSS APPLY sys.dm_exec_query_plan ( cp.plan_handle ) qp ;

Saya pikir pertanyaan yang menyebabkan kompilasi harus yang dengan objtype = Adhoc tetapi ini juga bisa berhubungan dengan kompilasi ulang. Sekarang saya harus menjalankan profiler, menangkap query yang menyebabkan kompilasi ulang dan kemudian mengeluarkannya dari daftar di atas.

Apakah saya pergi ke arah yang benar?

Apakah ada satu query yang bisa saya gunakan untuk mencapai hanya kompilasi SQL tanpa terlalu banyak bekerja?

Sumber daya yang membantu saya mencapai pengetahuan di atas:

http://social.msdn.microsoft.com/Forums/en/sqldatabaseengine/thread/954b4fba-3774-42e3-86e7-e5172abe0c83 http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=143946 http: //technet.microsoft.com/en-nz/library/cc966425(en-us).aspx
http://www.sqlservercentral.com/Forums/Topic914951-360-1.aspx

Bantuan apa pun sangat dihargai.

Manjot
sumber

Jawaban:

7

Saya tidak berpikir Anda dapat menemukan ini dengan cara yang mudah tetapi tetap mungkin untuk melewati ini. Profiler menawarkan banyak tipe kelas peristiwa yang dapat digunakan dalam menganalisis kinerja kueri. Mulai sesi Profiler baru dan periksa acara berikut:

Performance: Performance statistics
Stored Procedures: RPC:Completed
TSQL: SQL:BatchCompleted
TSQL: SQL: BatchStarting

Centang untuk Tampilkan semua kolom dan pilih masing-masing kolom di bawah Kinerja: Hanya statistik kinerja acara. Sisa acara dapat dibiarkan dengan pengaturan default.

Selanjutnya, Pilih Filter Kolom dan filter berdasarkan DatabaseName dan / atau LoginName / ApplicationName / HostName dll., Jika Anda mengetahuinya. Tujuannya adalah untuk membatasi jumlah baris yang dibuang di Profiler dan hanya berkonsentrasi pada kebutuhan Anda.

Selanjutnya, tekan Jalankan dan biarkan berjalan selama beberapa saat (2-3 menit selama yang Anda butuhkan). Menganalisis hasil yang dilumpuhkan dengan melihat pada: Peristiwa statistik kinerja.

Jika Statistik Kinerja akan sering terjadi, itu berarti bahwa rencana kueri di-cache untuk pertama kalinya, dikompilasi, dikompilasi ulang, atau diusir dari PlanCache. Dari pengetahuan saya jika permintaan tidak memiliki rencana kueri di Plan Cache - Anda akan melihat 2 baris acara PerformanceStatistics dan diikuti oleh SQL: BatchStarting , lalu SQL: BatchCompleted . Ini berarti bahwa Rencana Kueri pertama kali dikompilasi, di-cache dan kemudian permintaan dimulai dan selesai.

Lihatlah kolom-kolom berikut dalam acara Statistik Kinerja:

SPID - ID of the session on which the event occurred. You can use it to identify the       
       row on SQL:BatchCompleted event which will display the SQL Query text and other  
       usefull information (Read/Writes, StartTime/EndTime)
Duration - Total time, in microseconds, spent during compilation.
EventSubClass - 0 = New batch SQL text that is not currently present in the cache.
                1 = Queries within a stored procedure have been compiled.
                2 = Queries within an ad hoc SQL statement have been compiled.
                3 = A cached query has been destroyed and the historical performance         
                    data associated with the plan is about to be destroyed.
                4 = A cached stored procedure has been removed from the cache and the  
                    historical performance data associated with it is about to be 
                    destroyed.

                5 = A cached trigger has been removed from the cache and the historical  
                    performance data associated with it is about to be destroyed.

Mempertimbangkan nomor EventSubClass Anda dapat mengetahui apa yang terjadi dengan Rencana Kueri dan mengambil langkah-langkah spesifik. Selain itu Anda dapat menambahkan kolom lainnya ke Prosedur Tersimpan dan Kelas Acara TSQL jika Anda berada di HostName, WindowsUser, atau info lainnya dari jejak Profiler. Juga jejak dapat disimpan dalam tabel SQL yang membuat analisis lebih mudah dan lebih dapat disesuaikan. Berikut ini tautan yang menjelaskan lebih lanjut tentang Kelas Peristiwa Statistik Kinerja.

yrushka
sumber
4

Baiklah, pertama mari kita lihat apakah ada tekanan pada cache.

select bpool_visible from sys.dm_os_sys_info
go

Lipat gandakan angka tersebut dengan 8 untuk mendapatkan memori dalam K. 75% dari ini dari 0-4G + 10% dari ini dari 4G-64G + 5% lagi adalah batas tekanan cache cache . Jika Anda mencapai 75% dari batas ini, SQL Server akan mulai membersihkan paket dari cache. Pembersihan ini terjadi ketika rencana kueri baru ditambahkan ke cache, sehingga utas akan berhenti untuk melakukan pekerjaan ini. Hal kedua yang dapat menyebabkan rencana untuk dibersihkan adalah jika jumlah paket melebihi 4x jumlah keranjang hash (tabel hash memetakan plan_handle ke paket). Ada 10.000 pada sistem 32-bit dan 40.000 pada sistem 64-bit.

select type, sum(pages_allocated_count) as pages_used from sys.dm_os_memory_objects 
where type in ('MEMOBJ_CACHESTOREOBJCP', 'MEMOBJ_CACHESTORESQLCP', 'MEMOBJ_CACHESTOREXPROC')
group by type
go

Keputusan tentang apa yang harus dibersihkan tidak dilakukan pada penggunaan, tetapi pada biaya rencana, rencana termurah dibersihkan terlebih dahulu (biaya untuk menghasilkan, bukan untuk mengeksekusi). Anda dapat melihat ini jika Anda menambahkan kolom original_costdan current_costke kueri Anda aktif sys.dm_exec_cached_plans. Paket ad-hoc dimulai dari 0, dan bertambah 1 setiap kali digunakan. Ketika tekanan cache terjadi, SQL Server mengurangi setengah dari setiap biaya, lalu membersihkan yang sudah mencapai 0.

Jika Anda memiliki banyak ad-hoc SQL, coba:

exec sp_reconfigure 'optimize for ad hoc workloads', 1
go
reconfigure
go

Dalam mode ini, SQL Server hanya cache "rintisan", berukuran sekitar 300 byte (rencana kueri normal adalah 24k minimum), berisi hash dan pointer ke teks SQL, pertama kali ia melihat pernyataan SQL tertentu, kemudian selanjutnya cache rencana lengkap jika dijalankan lagi. Ini tidak harus mengurangi kompilasi dengan sendirinya, tetapi itu akan mengurangi tekanan memori pada cache rencana.

Catatan: Ini berfungsi pada 2008, bukan mencobanya pada 2005.

Trik lain adalah

alter database ... set parameterization forced
go

Ini akan menyebabkan SQL Server memperlakukan konstanta sebagai parameter, yang dapat membantu dengan fitur autoparameterisasi yang biasanya menyimpan rencana untuk pernyataan SQL yang serupa. Ad-hoc SQL harus memiliki cache rencana cached, kecuali jika server Anda sangat kekurangan memori, tetapi ini bergantung pada pencocokan tekstual yang tepat kecuali dapat diparameterisasi, dalam hal ini berperilaku lebih seperti kueri yang disiapkan.

Gayus
sumber
Terima kasih! Saya tahu opsi "parameterisasi paksa" ini, tetapi takut menggunakannya. Satu-satunya kelemahan yang bisa saya lihat dalam menggunakan ini adalah ia akan mengisi cache. Apakah saya benar?
Manjot
3

Apakah Anda sering menjalankan pekerjaan SQL Server di kotak ini? Perhatikan bahwa pada tahun 2005 permintaan pekerjaan agen TIDAK di-cache dan dapat menyebabkan kompilasi bloat & sql juga.

Lihatlah jumlah paket dengan jumlah penggunaan kembali yang rendah. Itulah pelakunya.

Beberapa catatan terkait tentang caching paket di bawah.

http://www.sqlskills.com/BLOGS/KIMBERLY/post/Plan-cache-adhoc-workloads-and-clearing-the-single-use-plan-cache-bloat.aspx

http://www.sqlskills.com/BLOGS/KIMBERLY/post/Clearing-the-cache-are-there-other-options.aspx

Sankar Reddy
sumber
0

Efek ini dikenal sebagai "polusi rencana kueri", di mana banyak query SQL serupa menghasilkan rencana eksekusi yang terpisah, tetapi setara.

Kueri Ad-Hoc menyebabkan overhead oleh penguraian individu, tetapi biasanya bukan kueri rencana polusi, karena rencana mereka tidak disimpan. Ini berbeda untuk kueri dengan hanya satu parameter (di bawah MS SQL Server), ini akan diperlakukan seperti permintaan parameter.

Ada beberapa kasus umum untuk pencemaran paket permintaan:

  • Permintaan SQL dengan hanya satu parameter literal kode keras (seperti 'pilih id, nama dari orang di mana id = 1234')
  • terutama jika digunakan dengan perintah / prosedur tersimpan yang memaksa database untuk menyimpan rencana kueri, seperti 'sp_prepexec' atau sp_executesql 'di bawah MSSQL (saya pikir' jalankan langsung 'di bawah Oracle bekerja dengan cara yang sama)
  • sebagian pertanyaan parameter, dengan variasi besar dalam nilai literal 'dikodekan', seperti 'pilih * dari SoccerMatches sm where sm.Date>?' dan sm.Tanggal <? dan HomeClubId = 5678 dan GuestClubId = 1234 '. Ini akan menyimpan rencana kueri karena parameter, tetapi membuat rencana kueri baru untuk setiap HomeClub atau GuestClub yang diubah (khususnya karena nilai Tanggal / Waktu adalah kesempatan yang bagus untuk memperkenalkan parameter di banyak API DB, ketika kueri gagal karena tanggal yang berbeda secara lokal format).
  • Sumber lain dari pencemaran paket permintaan mungkin kerangka kerja seperti ADO.NET dengan driver tidak mencukupi, dalam kombinasi dengan nilai string / (n) varchar. Beberapa implementasi / driver akan menetapkan ukuran parameter ke panjang string aktual, menyebabkan rencana kueri terpisah untuk setiap panjang parameter string yang berbeda dalam kueri. Praktik terbaik tampaknya adalah penggunaan ukuran bidang maksimum (mis. Varchar (4000)), atau driver yang menempatkan panjang yang benar
Erik Hart
sumber