Saya yakin Anda akan melihat gejala ini jika Anda memiliki BANYAK rencana kueri besar yang berjuang untuk memori agar dapat dikompilasi (ini sangat sedikit hubungannya dengan menjalankan kueri itu sendiri). Untuk mencapai ini, saya curiga Anda menggunakan ORM atau semacam aplikasi yang menghasilkan banyak pertanyaan unik namun relatif kompleks. SQL Server dapat berada di bawah tekanan memori karena hal-hal seperti operasi permintaan besar, tetapi pada pemikiran lebih lanjut lebih mungkin hanya bahwa sistem Anda dikonfigurasi dengan memori jauh lebih sedikit daripada yang dibutuhkan (baik tidak pernah ada cukup memori untuk memenuhi semua permintaan Anda Sedang mencoba untuk mengkompilasi, atau ada proses lain pada kotak yang mencuri memori dari SQL Server).
Anda dapat melihat apa yang dikonfigurasi dengan SQL Server menggunakan:
EXEC sp_configure 'max server memory'; -- max configured in MB
SELECT counter_name, cntr_value
FROM sys.dm_os_performance_counters
WHERE counter_name IN
(
'Total Server Memory (KB)', -- max currently granted
'Target Server Memory (KB)' -- how much SQL Server wished it had
);
Anda dapat mengidentifikasi paket cache yang membutuhkan memori paling kompilasi dengan permintaan Jonathan Kehayias berikut , yang sedikit diadaptasi:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
;WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
SELECT TOP (10) CompileTime_ms, CompileCPU_ms, CompileMemory_KB,
qs.execution_count,
qs.total_elapsed_time/1000.0 AS duration_ms,
qs.total_worker_time/1000.0 as cputime_ms,
(qs.total_elapsed_time/qs.execution_count)/1000.0 AS avg_duration_ms,
(qs.total_worker_time/qs.execution_count)/1000.0 AS avg_cputime_ms,
qs.max_elapsed_time/1000.0 AS max_duration_ms,
qs.max_worker_time/1000.0 AS max_cputime_ms,
SUBSTRING(st.text, (qs.statement_start_offset / 2) + 1,
(CASE qs.statement_end_offset
WHEN -1 THEN DATALENGTH(st.text) ELSE qs.statement_end_offset
END - qs.statement_start_offset) / 2 + 1) AS StmtText,
query_hash, query_plan_hash
FROM
(
SELECT
c.value('xs:hexBinary(substring((@QueryHash)[1],3))', 'varbinary(max)') AS QueryHash,
c.value('xs:hexBinary(substring((@QueryPlanHash)[1],3))', 'varbinary(max)') AS QueryPlanHash,
c.value('(QueryPlan/@CompileTime)[1]', 'int') AS CompileTime_ms,
c.value('(QueryPlan/@CompileCPU)[1]', 'int') AS CompileCPU_ms,
c.value('(QueryPlan/@CompileMemory)[1]', 'int') AS CompileMemory_KB,
qp.query_plan
FROM sys.dm_exec_cached_plans AS cp
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp
CROSS APPLY qp.query_plan.nodes('ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple') AS n(c)
) AS tab
JOIN sys.dm_exec_query_stats AS qs ON tab.QueryHash = qs.query_hash
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
ORDER BY CompileMemory_KB DESC
OPTION (RECOMPILE, MAXDOP 1);
Anda dapat melihat bagaimana cache rencana digunakan dengan yang berikut ini:
SELECT objtype, cacheobjtype,
AVG(size_in_bytes*1.0)/1024.0/1024.0,
MAX(size_in_bytes)/1024.0/1024.0,
SUM(size_in_bytes)/1024.0/1024.0,
COUNT(*)
FROM sys.dm_exec_cached_plans
GROUP BY GROUPING SETS ((),(objtype, cacheobjtype))
ORDER BY objtype, cacheobjtype;
Saat Anda mengalami semafor tinggi menunggu, periksa untuk melihat apakah hasil kueri ini berbeda secara signifikan dari selama aktivitas "normal":
SELECT resource_semaphore_id, -- 0 = regular, 1 = "small query"
pool_id,
available_memory_kb,
total_memory_kb,
target_memory_kb
FROM sys.dm_exec_query_resource_semaphores;
SELECT StmtText = SUBSTRING(st.[text], (qs.statement_start_offset / 2) + 1,
(CASE qs.statement_end_offset
WHEN -1 THEN DATALENGTH(st.text) ELSE qs.statement_end_offset
END - qs.statement_start_offset) / 2 + 1),
r.start_time, r.[status], DB_NAME(r.database_id), r.wait_type,
r.last_wait_type, r.total_elapsed_time, r.granted_query_memory,
m.requested_memory_kb, m.granted_memory_kb, m.required_memory_kb,
m.used_memory_kb
FROM sys.dm_exec_requests AS r
INNER JOIN sys.dm_exec_query_stats AS qs
ON r.plan_handle = qs.plan_handle
INNER JOIN sys.dm_exec_query_memory_grants AS m
ON r.request_id = m.request_id
AND r.plan_handle = m.plan_handle
CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS st;
Dan Anda mungkin juga ingin melihat dan melihat bagaimana memori didistribusikan:
DBCC MEMORYSTATUS;
Dan ada beberapa informasi bagus di sini tentang mengapa Anda mungkin melihat banyak kompilasi / kompilasi (yang akan berkontribusi pada penantian itu):
http://technet.microsoft.com/en-us/library/ee343986(v=sql.100).aspx
http://technet.microsoft.com/en-us/library/cc293620.aspx
Anda dapat memeriksa jumlah kompilasi / kompilasi ulang yang tinggi menggunakan penghitung berikut:
SELECT counter_name, cntr_value
FROM sys.dm_os_performance_counters
WHERE counter_name IN
(
'SQL Compilations/sec',
'SQL Re-Compilations/sec'
);
Dan Anda dapat memeriksa tekanan memori internal yang mengarah ke penggusuran - penghitung non-nol di sini akan menunjukkan bahwa sesuatu yang tidak baik sedang terjadi dengan cache rencana:
SELECT * FROM sys.dm_os_memory_cache_clock_hands
WHERE [type] IN (N'CACHESTORE_SQLCP', N'CACHESTORE_OBJCP');
CATATAN Sebagian besar metrik ini tidak memiliki keajaiban "ya ampun, saya perlu panik atau melakukan sesuatu!" ambang. Yang perlu Anda lakukan adalah melakukan pengukuran selama aktivitas sistem normal , dan menentukan di mana ambang batas ini untuk perangkat keras, konfigurasi, dan beban kerja Anda. Ketika Anda panik melakukan sesuatu adalah ketika dua kondisi itu benar:
- metrik bervariasi secara signifikan dari nilai normal; dan,
- sebenarnya ada masalah kinerja yang terjadi (seperti paku CPU Anda) - tetapi hanya jika mereka benar-benar mengganggu apa pun. Selain melihat lonjakan CPU, apakah Anda melihat gejala lain? Dengan kata lain, apakah lonjakan gejala, atau apakah lonjakan menyebabkan gejala lain? Apakah pengguna sistem akan memperhatikan? Banyak orang selalu mengejar konsumen yang menunggu tertinggi mereka, hanya karena itu yang tertinggi. Sesuatu akan selalu menjadi konsumen tunggu tertinggi - Anda harus tahu bahwa itu cukup bervariasi dari aktivitas normal yang mengindikasikan masalah atau perubahan signifikan.
Optimize for ad hoc workloads
adalah pengaturan yang tepat untuk 99% dari beban kerja di luar sana, tetapi itu tidak akan sangat membantu dalam mengurangi biaya kompilasi - ini bertujuan untuk mengurangi rembesan cache rencana dengan mencegah rencana penggunaan tunggal menyimpan seluruh paket sampai dijalankan dua kali . Bahkan ketika Anda hanya menyimpan rintisan di cache paket, Anda masih harus mengkompilasi paket lengkap untuk pelaksanaan kueri. Mungkin yang ingin direkomendasikan oleh @ Kahn adalah mengatur parameterisasi tingkat basis data untuk dipaksakan , yang berpotensi memberikan rencana penggunaan kembali yang lebih baik (tapi itu benar-benar tergantung pada seberapa unik semua permintaan biaya tinggi ini).
Juga beberapa informasi yang baik dalam buku putih ini tentang caching dan kompilasi rencana.
Optimize for ad hoc workloads
set, seperti yang Anda sebutkan, itu tidak benar-benar relevan dengan masalah khusus ini. Kami memiliki kode yang menghasilkan banyak pertanyaan unik, beberapa dari alat ORM, beberapa kode tangan. Sejauh yang saya tahu, lonjakan CPU tidak terjadi cukup lama bagi pengguna kami untuk melihat. Mengatur basis data ke parameterisasi paksa terdengar berbahaya bagi saya.Alasan yang paling khas sejauh ini yang telah saya lihat menunggu itu muncul, adalah sebagai akibat dari indeks terfragmentasi atau tidak cukup, dan statistik yang memiliki ukuran sampel tidak cukup, atau usang. Ini menghasilkan pemindaian tabel lengkap yang besar yang memonopoli semua memori, yang pada gilirannya menghasilkan gejala yang sering kita lihat sebagai RESOURCE_SEMAPHORE_QUERY_COMPILE.
Cara termudah untuk memverifikasi ini adalah dengan memeriksa apakah kueri menjalankan pemindaian tabel penuh / pemindaian indeks, ketika mereka harus melakukan pencarian indeks. Jika Anda memiliki kueri masalah yang dengannya Anda dapat mereproduksi masalah - menjadi sangat mudah untuk mendiagnosis dan memperbaikinya.
Saya akan memeriksa indeks pada tabel yang dipengaruhi oleh pertanyaan masalah - yaitu. periksa fragmentasi indeks, indeks potensial yang difilter yang tidak digunakan, hilang indeks yang mungkin ingin Anda buat, dll. Juga, perbarui statistik mereka dengan FULLSCAN sesegera mungkin.
Poin yang baik untuk diingat adalah bahwa tabel masalah Anda mungkin bukan satu-satunya yang membutuhkan ini. Misalnya, jika Anda memiliki kueri yang mengambil data dari 10 tabel, perencana eksekusi kadang-kadang dapat menunjukkan bahwa itu tidak menggunakan indeks pada tabel 1, tetapi ketika Anda kemudian memeriksa indeks pada tabel 1, itu sebenarnya ok. Perencana kueri dapat memutuskan untuk mengambil data pada tabel 1 dengan pemindaian tabel lengkap dengan benar, karena indeks yang salah / tidak cukup pada tabel 7 misalnya, mengembalikan begitu banyak data sehingga ini akan menjadi pilihan yang lebih cepat. Jadi mendiagnosis ini terkadang sulit.
Juga, jika Anda memiliki banyak kueri kode-kode dengan hanya beberapa perubahan dalam nilai variabel misalnya, Anda mungkin ingin melihat pengaktifan pengoptimalan untuk beban kerja ad hoc . Pada dasarnya apa yang dilakukannya adalah menyimpan potongan rintisan dari rencana yang disusun alih-alih keseluruhan rencana, menghemat sumber daya ketika Anda tidak pernah mendapatkan rencana yang persis sama setiap saat.
sumber