Tôi tin rằng bạn sẽ thấy triệu chứng này nếu bạn có RẤT NHIỀU kế hoạch truy vấn lớn đang đấu tranh cho bộ nhớ để biên dịch (điều này rất ít liên quan đến việc chạy chính truy vấn). Để đạt được điều này, tôi nghi ngờ bạn đang sử dụng ORM hoặc một loại ứng dụng nào đó tạo ra nhiều truy vấn độc đáo nhưng tương đối phức tạp. SQL Server có thể chịu áp lực bộ nhớ vì những thứ như hoạt động truy vấn lớn, nhưng nghĩ thêm có khả năng là hệ thống của bạn được cấu hình với bộ nhớ ít hơn nhiều so với nhu cầu (hoặc không bao giờ có đủ bộ nhớ để đáp ứng tất cả các truy vấn bạn Đang cố gắng biên dịch hoặc có các quy trình khác trên hộp đang đánh cắp bộ nhớ từ SQL Server).
Bạn có thể xem SQL Server được cấu hình bằng cách sử dụng:
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
);
Bạn có thể xác định các gói được lưu trong bộ nhớ cache yêu cầu bộ nhớ biên dịch nhiều nhất với truy vấn Jonathan Kehayias sau đây , được điều chỉnh một chút:
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);
Bạn có thể thấy cách bộ đệm kế hoạch đang được sử dụng với những điều sau đây:
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;
Khi bạn gặp phải tình trạng chờ đợi semaphore cao, hãy kiểm tra xem liệu các kết quả truy vấn này có thay đổi đáng kể so với trong hoạt động "bình thường" không:
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;
Và bạn cũng có thể muốn xem và xem cách phân phối bộ nhớ:
DBCC MEMORYSTATUS;
Và có một số thông tin tốt ở đây về lý do tại sao bạn có thể thấy số lượng biên dịch / biên dịch lại cao (sẽ đóng góp cho sự chờ đợi đó):
http://technet.microsoft.com/en-us/library/ee343986(v=sql.100).aspx
http://technet.microsoft.com/en-us/library/cc293620.aspx
Bạn có thể kiểm tra số lượng biên dịch / biên dịch lại cao bằng các bộ đếm sau:
SELECT counter_name, cntr_value
FROM sys.dm_os_performance_counters
WHERE counter_name IN
(
'SQL Compilations/sec',
'SQL Re-Compilations/sec'
);
Và bạn có thể kiểm tra áp suất bộ nhớ trong dẫn đến việc trục xuất - các bộ đếm khác không ở đây sẽ chỉ ra rằng điều gì đó không tốt đang xảy ra với bộ đệm của kế hoạch:
SELECT * FROM sys.dm_os_memory_cache_clock_hands
WHERE [type] IN (N'CACHESTORE_SQLCP', N'CACHESTORE_OBJCP');
LƯU Ý Hầu hết các số liệu này không có phép thuật "trời ơi tôi cần phải hoảng sợ hoặc làm gì đó!" ngưỡng. Những gì bạn cần làm là thực hiện các phép đo trong quá trình hoạt động bình thường của hệ thống và xác định các ngưỡng này dành cho phần cứng, cấu hình và khối lượng công việc của bạn. Khi bạn hoảng loạn làm điều gì đó là khi hai điều kiện là đúng:
- các số liệu khác nhau đáng kể từ các giá trị bình thường; và,
- thực sự có một vấn đề về hiệu năng xảy ra (như CPU của bạn tăng đột biến) - nhưng chỉ khi chúng thực sự can thiệp vào bất cứ điều gì. Ngoài việc thấy CPU tăng đột biến, bạn có thấy bất kỳ triệu chứng nào khác không? Nói cách khác, sự tăng đột biến là triệu chứng, hay là sự tăng đột biến gây ra các triệu chứng khác? Người dùng của hệ thống có bao giờ nhận thấy? Rất nhiều người luôn theo đuổi người tiêu dùng chờ đợi cao nhất của họ, đơn giản vì đó là mức cao nhất. Một cái gì đó luôn luôn là người tiêu dùng chờ đợi cao nhất - bạn phải biết rằng nó thay đổi đủ so với hoạt động bình thường mà nó chỉ ra một vấn đề hoặc một số thay đổi đáng kể.
Optimize for ad hoc workloads
là một thiết lập tuyệt vời cho 99% khối lượng công việc ngoài kia, nhưng sẽ không hữu ích lắm trong việc giảm chi phí biên dịch - nó nhằm mục đích giảm sự phình to bộ nhớ cache của kế hoạch bằng cách ngăn kế hoạch sử dụng một lần lưu trữ toàn bộ kế hoạch cho đến khi nó được thực hiện hai lần . Ngay cả khi bạn chỉ lưu trữ sơ khai trong bộ đệm của kế hoạch, bạn vẫn phải biên dịch toàn bộ kế hoạch để thực hiện truy vấn. Có lẽ điều mà @Kahn muốn đề xuất là đặt tham số hóa mức cơ sở dữ liệu thành bắt buộc , điều này sẽ có khả năng cung cấp việc sử dụng lại kế hoạch tốt hơn (nhưng nó thực sự phụ thuộc vào mức độ duy nhất của tất cả các truy vấn chi phí cao này).
Ngoài ra một số thông tin tốt trong bài báo trắng này về kế hoạch lưu trữ và bộ nhớ đệm.
Optimize for ad hoc workloads
Tuy nhiên, hiện tại chúng tôi có bộ, như bạn đã đề cập, nó không thực sự liên quan đến vấn đề cụ thể này. Chúng tôi có mã tạo ra rất nhiều truy vấn duy nhất, một số từ một công cụ ORM, một số được mã hóa bằng tay. Theo tôi biết, các đột biến CPU không xảy ra đủ lâu để người dùng của chúng tôi chú ý. Đặt cơ sở dữ liệu thành tham số bắt buộc nghe có vẻ nguy hiểm đối với tôi.