Bagaimana cara menghapus paket buruk spesifik dari cache kueri SQL Server?

33

Kami memiliki satu permintaan SQL Server 2008 tertentu (bukan proc yang disimpan, tetapi string SQL yang sama - dijalankan setiap 5 menit) yang sebentar-sebentar menyimpan rencana kueri yang sangat buruk.

Kueri ini biasanya berjalan dalam beberapa milidetik, tetapi dengan rencana kueri yang buruk ini, dibutuhkan 30+ detik.

Bagaimana cara operasi menghapus hanya satu rencana kuota cache yang buruk dari SQL Server 2008, tanpa menghilangkan seluruh cache kueri pada server database produksi?

Jeff Atwood
sumber

Jawaban:

39

Saya menemukan beberapa hal

select * from sys.dm_exec_query_stats

akan menampilkan semua paket permintaan yang di-cache. Sayangnya, tidak ada teks SQL yang ditampilkan di sana.

Namun, Anda dapat bergabung dengan teks SQL ke paket seperti:

select plan_handle, creation_time, last_execution_time, execution_count, qt.text
FROM 
   sys.dm_exec_query_stats qs
   CROSS APPLY sys.dm_exec_sql_text (qs.[sql_handle]) AS qt

Dari sini cukup sepele untuk menambahkan WHEREklausa untuk menemukan SQL yang saya tahu ada dalam kueri, dan kemudian saya dapat menjalankan:

DBCC FREEPROCCACHE (plan_handle_id_goes_here)

untuk menghapus setiap paket permintaan dari cache paket permintaan. Tidak persis mudah atau nyaman, tetapi tampaknya berfungsi ..

sunting: membuang seluruh cache permintaan juga akan berfungsi, dan lebih tidak berbahaya daripada yang terdengar, setidaknya dalam pengalaman saya:

DBCC FREESYSTEMCACHE ('ALL') WITH MARK_IN_USE_FOR_REMOVAL;
Jeff Atwood
sumber
2
saran untuk menggunakan petunjuk rencana tidak kurang dari itu.
Remus Rusanu
1
Saya menemukan ini setelah permintaan saya secara ajaib diperbarui itu adalah rencana yang buruk tetapi saya berencana untuk mengujinya lain kali. Petunjuk paket tidak membantu jika kueri menderita 'opsional-itis' - yang memiliki banyak parameter opsional dan telah dioptimalkan untuk satu set, kemudian jalankan untuk set yang berbeda. Tidak ada rencana optimal yang dapat dilampirkan untuk permintaan semacam ini. Ada rencana optimal untuk satu set parameter yang pada gilirannya mengerikan untuk set parameter lainnya.
Nick.McDermaid
6

Jika Anda tahu bagaimana rencana yang baik itu, gunakan saja petunjuk rencana .

Anda tidak dapat menghapus entri cache tertentu, tetapi Anda dapat membersihkan seluruh kumpulan cache dengan DBCC FREESYSTEMCACHE(cachename/poolname).

Anda bisa mendapatkan nama cache dari paket kueri yang buruk jika Anda memiliki pegangan paket (dari sys.dm_exec_requests.plan_handle untuk session_id yang bermasalah selama eksekusi, atau dari sys.dm_exec_query_stats pasca eksekusi):

select ce.name
from sys.dm_exec_cached_plans cp
join sys.dm_os_memory_cache_entries ce on cp.memory_object_address = ce.memory_object_address
where cp.plan_handle = @bad_plan

Namun semua rencana SQL memiliki nama 'SQL Plans' yang menjadikan memilih yang tepat untuk DBCC FREESYSTEMCACHE ... pilihan sulit.

Memperbarui

Jangan lupa, lupakan DBCC FREEPROCCACHE(plan_handle), ya itu akan berhasil.

Remus Rusanu
sumber
1
Kemampuan untuk mengirimkan plan_handle ke DBCC FREEPROCCACHE tersedia dalam SQL Server 2008 dan tidak dalam SQL Server 2005.
Mario
Apa artinya jika sys.dm_exec_cached_planstidak ada entri di dalamnya untuk plan_handledari sys.dm_exec_requests?
Jonathan Gilbert
@ JonathanGilbert itu berarti rencana itu tidak di-cache, atau diusir dari cache. Lihat docs.microsoft.com/en-us/sql/relational-databases/…
Remus Rusanu
Jadi hanya untuk mengonfirmasi, meskipun saya baru saja mulai menjalankan kueri itu , dan kueri tidak memiliki petunjuk mengatakan untuk tidak men-cache, itu dapat di-uncached karena SQL Server membuat keputusan nilai untuk tidak men-cache itu? Itu tidak akan karena itu masih berjalan, kan? Jika ia memutuskan untuk men-cache rencana, maka itu akan di-cache langsung dari titik di mana kueri mulai berjalan?
Jonathan Gilbert
1

The FREEPROCCACHE solusi baik-baik saja, tapi cara yang lebih langsung untuk melakukan hal ini adalah dengan menggunakan OPTION (mengkompilasi ulang) pada Anda SQL String (Anda sebutkan itu bukan SP), ini menceritakan Engine nya rencana Single Use, karena kemungkinan Anda menduga ada Parameter Sniffing atau Statistik Anda secara drastis berbeda dari menjalankan ke menjalankan dan Anda menduga itu masalah Rencana Cached Buruk.

DECLARE @SQL NVARCHAR(4000)
SELECT @SQL = 'SELECT * FROM Table WHERE Column LIKE @NAME OPTION (RECOMPILE)'
EXEC sp_executesql @SQL, N'@NAME varchar(15)', 'MyName' 
CodeCowboyOrg
sumber