특정 인스턴스의 데이터베이스별로 CPU 사용량을 얻는 방법은 무엇입니까?


15

데이터베이스별로 CPU 사용량을 감지하는 다음 쿼리를 찾았지만 다른 결과가 표시됩니다.

WITH DB_CPU_Stats
AS
(
    SELECT DatabaseID, DB_Name(DatabaseID) AS [DatabaseName], 
      SUM(total_worker_time) AS [CPU_Time_Ms]
    FROM sys.dm_exec_query_stats AS qs
    CROSS APPLY (
                    SELECT CONVERT(int, value) AS [DatabaseID] 
                  FROM sys.dm_exec_plan_attributes(qs.plan_handle)
                  WHERE attribute = N'dbid') AS F_DB
    GROUP BY DatabaseID
)
SELECT ROW_NUMBER() OVER(ORDER BY [CPU_Time_Ms] DESC) AS [row_num],
       DatabaseName,
        [CPU_Time_Ms], 
       CAST([CPU_Time_Ms] * 1.0 / SUM([CPU_Time_Ms]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [CPUPercent]
FROM DB_CPU_Stats
--WHERE DatabaseID > 4 -- system databases
--AND DatabaseID <> 32767 -- ResourceDB
ORDER BY row_num OPTION (RECOMPILE);

위의 쿼리는 문제가 내 데이터베이스 중 하나 (거의 96 %)에 있음을 나타냅니다.

그리고 아래 쿼리는 마스터 및 배포 데이터베이스에 문제가 있음을 나타냅니다 (약 90 %).

DECLARE @total INT
SELECT @total=sum(cpu) FROM sys.sysprocesses sp (NOLOCK)
    join sys.sysdatabases sb (NOLOCK) ON sp.dbid = sb.dbid

SELECT sb.name 'database', @total 'system cpu', SUM(cpu) 'database cpu', CONVERT(DECIMAL(4,1), CONVERT(DECIMAL(17,2),SUM(cpu)) / CONVERT(DECIMAL(17,2),@total)*100) '%'
FROM sys.sysprocesses sp (NOLOCK)
JOIN sys.sysdatabases sb (NOLOCK) ON sp.dbid = sb.dbid
--WHERE sp.status = 'runnable'
GROUP BY sb.name
ORDER BY CONVERT(DECIMAL(4,1), CONVERT(DECIMAL(17,2),SUM(cpu)) / CONVERT(DECIMAL(17,2),@total)*100) desc

내가 sys.sysprocesses거부 되는 것을 확인 했습니다. 이것은 두 번째 쿼리의 결과가 잘못되었음을 의미합니까?

답변:


14

@Thomas와 마찬가지로 "데이터베이스 당 CPU 사용량"이 정확하거나 유용하다는 문제에 대한 질문에 대한 의견에서 @Aaron에 전적으로 동의하지만 적어도 두 쿼리가 왜 그렇게되는지에 대한 질문에 대답 할 수 있습니다. 다른. 그리고 그들이 다른 이유는 어느 것이 더 정확한지를 나타내지 만, 더 높은 수준의 정확도는 여전히 정확하지 않은 정확도에 비해 여전히 정확하지 않으므로 ;-).

첫 번째 쿼리는 sys.dm_exec_query_stats 를 사용 하여 CPU 정보 (예 :) 를 가져옵니다 total_worker_time. 해당 DMV에 대한 MSDN 문서 인 링크 된 페이지로 이동하면 짧은 3 문장 소개와 2 문장의 문장이이 정보의 맥락을 이해하는 데 필요한 대부분의 정보를 제공합니다 ( "얼마나 믿을만한가?" 그리고 "어떻게 비교 sys.sysprocesses"). 이 두 문장은 다음과 같습니다.

SQL Server에서 캐시 된 쿼리 계획에 대한 집계 성능 통계를 반환합니다. ... 계획이 캐시에서 제거되면 해당 행이이보기에서 제거됩니다.

첫 번째 문장 인 " 집계 성능 통계를 리턴 합니다"는이 DMV의 정보 (여러 다른 것과 마찬가지로)가 누적되며 현재 실행중인 쿼리에만 국한되지 않음을 알려줍니다. 이것은 또한 질문의 쿼리에 포함되지 않은 DMV의 필드로 표시되며 execution_count이는 다시 누적 데이터임을 나타냅니다. 그리고 일부 메트릭을로 나누어 평균 등을 얻을 수 있으므로이 데이터를 누적하는 것이 매우 편리합니다 execution_count.

두 번째 문장 인 "캐시에서 제거되는 계획도이 DMV에서 제거됩니다"는 서버가 이미 전체 계획 캐시를 가지고 있고로드 중이므로 계획이 만료되는 경우 전체 그림이 아님을 나타냅니다. 다소 자주. 또한 대부분의 DMV는 서버가 재설정 될 때 재설정되므로 계획이 만료 될 때 이러한 행이 제거되지 않은 경우에도 실제 히스토리가 아닙니다.

위와를 대조해 봅시다 sys.sysprocesses. 이 시스템보기는 sys.dm_exec_connections , sys.dm_exec_sessionssys.dm_exec_requests 의 조합 (현재 링크 된 페이지에 표시 sys.dm_exec_sessions) 과 같이 현재 실행중인 항목 만 표시합니다 . 이것은 sys.dm_exec_query_stats프로세스가 완료된 후에도 데이터를 보유하는 DMV 와 비교할 때 서버에 대해 완전히 다른 관점입니다 . "두 번째 쿼리의 결과가 잘못 되었습니까?"와 관련하여 의미합니다. 문제는 틀린 것이 아니라 단지 성능 통계의 다른 측면 (즉, 시간대)과 관련이 있다는 것입니다.

따라서 사용하는 쿼리 sys.sysprocesses는 "지금"만보고 있습니다. 그리고 사용하는 쿼리 는 SQL Server 서비스를 마지막으로 다시 시작한 이후 (또는 분명히 시스템을 재부팅 한 후) 발생한 일 sys.dm_exec_query_stats주로 보고 있습니다. 일반적인 성능 분석의 경우 sys.dm_exec_query_stats훨씬 나은 것으로 보이지만 다시 유용한 정보를 항상 삭제합니다. 그리고 두 경우 모두 처음에 "database_id"값의 정확성과 관련하여 @Aaron이 질문 설명에서 삭제 한 점을 고려해야합니다 (즉, 코드를 시작한 활성 DB 만 반영 함). "문제"가 반드시 발생하는 것은 아닙니다.)

당신은 단지 필요하지만, / 일 지금 둔화되는 가능성이 있기 때문에, 당신의 조합을 사용하는 것이 더 낫다, 모든 데이터베이스에서 지금 무슨 일이 일어나고 있는지의 감각을 얻고 싶은 sys.dm_exec_connections, sys.dm_exec_sessions그리고 sys.dm_exec_requests(그리고 사용되지 않는 sys.sysprocesses). 쿼리는 여러 데이터베이스에서 결합 될 수 있고 하나 이상의 데이터베이스의 UDF 등을 포함 할 수 있으므로 데이터베이스가 아닌 쿼리를 찾고 있습니다.


편집 :
전반적인 관심사가 CPU 소비를 줄이면 데이터베이스가 실제로 CPU를 차지하지 않기 때문에 CPU를 가장 많이 차지하는 쿼리를 찾으십시오 (데이터베이스가 분리되어 있고 각 데이터베이스가 격리되어있는 호스팅 회사에서 데이터베이스별로 작동 할 수 있음) 다른 고객이 소유).

다음 쿼리는 평균 CPU 사용량이 높은 쿼리를 식별하는 데 도움이됩니다. 이러한 레코드는 각각 다른 실행 계획을 가진 동일한 쿼리 (예, 쿼리 배치의 동일한 서브 세트)를 여러 번 표시 할 수 있으므로 query_stats DMV의 데이터를 압축합니다.

;WITH cte AS
(
  SELECT stat.[sql_handle],
         stat.statement_start_offset,
         stat.statement_end_offset,
         COUNT(*) AS [NumExecutionPlans],
         SUM(stat.execution_count) AS [TotalExecutions],
         ((SUM(stat.total_logical_reads) * 1.0) / SUM(stat.execution_count)) AS [AvgLogicalReads],
         ((SUM(stat.total_worker_time) * 1.0) / SUM(stat.execution_count)) AS [AvgCPU]
  FROM sys.dm_exec_query_stats stat
  GROUP BY stat.[sql_handle], stat.statement_start_offset, stat.statement_end_offset
)
SELECT CONVERT(DECIMAL(15, 5), cte.AvgCPU) AS [AvgCPU],
       CONVERT(DECIMAL(15, 5), cte.AvgLogicalReads) AS [AvgLogicalReads],
       cte.NumExecutionPlans,
       cte.TotalExecutions,
       DB_NAME(txt.[dbid]) AS [DatabaseName],
       OBJECT_NAME(txt.objectid, txt.[dbid]) AS [ObjectName],
       SUBSTRING(txt.[text], (cte.statement_start_offset / 2) + 1,
       (
         (CASE cte.statement_end_offset 
           WHEN -1 THEN DATALENGTH(txt.[text])
           ELSE cte.statement_end_offset
          END - cte.statement_start_offset) / 2
         ) + 1
       )
FROM cte
CROSS APPLY sys.dm_exec_sql_text(cte.[sql_handle]) txt
ORDER BY cte.AvgCPU DESC;

이다 AvgCPU밀리 초 단위로?
Kolob Canyon

안녕하세요 @KolobCanyon. sys.dm_exec_query_stats 의 문서에 따르면 , total_worker_time" 이 계획이 컴파일 된 이후 실행으로 소비 된 총 CPU 시간 (마이크로 초 (밀리 초) 만보고 됨) "입니다. 도움이 되나요? 그것이 당신이보고 싶은 것이라면 그것은 밀리 초로 쉽게 변환 될 수 있습니다.
Solomon Rutzky 2016 년

1

0으로 나누기 쿼리를 오류로 조정하고 Excel로 복사 / 붙여 넣기에 대한 열 이름을 최적화했습니다.

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
GO
WITH DB_CPU_Stats
AS
(
    SELECT DatabaseID, isnull(DB_Name(DatabaseID),case DatabaseID when 32767 then 'Internal ResourceDB' else CONVERT(varchar(255),DatabaseID)end) AS [DatabaseName], 
      SUM(total_worker_time) AS [CPU_Time_Ms],
      SUM(total_logical_reads)  AS [Logical_Reads],
      SUM(total_logical_writes)  AS [Logical_Writes],
      SUM(total_logical_reads+total_logical_writes)  AS [Logical_IO],
      SUM(total_physical_reads)  AS [Physical_Reads],
      SUM(total_elapsed_time)  AS [Duration_MicroSec],
      SUM(total_clr_time)  AS [CLR_Time_MicroSec],
      SUM(total_rows)  AS [Rows_Returned],
      SUM(execution_count)  AS [Execution_Count],
      count(*) 'Plan_Count'
    FROM sys.dm_exec_query_stats AS qs
    CROSS APPLY (
                    SELECT CONVERT(int, value) AS [DatabaseID] 
                  FROM sys.dm_exec_plan_attributes(qs.plan_handle)
                  WHERE attribute = N'dbid') AS F_DB
    GROUP BY DatabaseID
)
SELECT ROW_NUMBER() OVER(ORDER BY [CPU_Time_Ms] DESC) AS [Rank_CPU],
       DatabaseName,
       [CPU_Time_Hr] = convert(decimal(15,2),([CPU_Time_Ms]/1000.0)/3600) ,
        CAST([CPU_Time_Ms] * 1.0 / SUM(case [CPU_Time_Ms] when 0 then 1 else [CPU_Time_Ms] end) OVER() * 100.0 AS DECIMAL(5, 2)) AS [CPU_Percent],
       [Duration_Hr] = convert(decimal(15,2),([Duration_MicroSec]/1000000.0)/3600) , 
       CAST([Duration_MicroSec] * 1.0 / SUM(case [Duration_MicroSec] when 0 then 1 else [Duration_MicroSec] end) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Duration_Percent],    
       [Logical_Reads],
        CAST([Logical_Reads] * 1.0 / SUM(case [Logical_Reads] when 0 then 1 else [Logical_Reads] end) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Logical_Reads_Percent],      
       [Rows_Returned],
        CAST([Rows_Returned] * 1.0 / SUM(case [Rows_Returned] when 0 then 1 else [Rows_Returned] end) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Rows_Returned_Percent],
       [Reads_Per_Row_Returned] = [Logical_Reads]/(case [Rows_Returned] when 0 then 1 else [Rows_Returned] end),
       [Execution_Count],
        CAST([Execution_Count] * 1.0 / SUM(case [Execution_Count]  when 0 then 1 else [Execution_Count] end) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Execution_Count_Percent],
       [Physical_Reads],
       CAST([Physical_Reads] * 1.0 / SUM(case [Physical_Reads] when 0 then 1 else [Physical_Reads] end ) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Physcal_Reads_Percent], 
       [Logical_Writes],
        CAST([Logical_Writes] * 1.0 / SUM(case [Logical_Writes] when 0 then 1 else [Logical_Writes] end) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Logical_Writes_Percent],
       [Logical_IO],
        CAST([Logical_IO] * 1.0 / SUM(case [Logical_IO] when 0 then 1 else [Logical_IO] end) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Logical_IO_Percent],
       [CLR_Time_MicroSec],
       CAST([CLR_Time_MicroSec] * 1.0 / SUM(case [CLR_Time_MicroSec] when 0 then 1 else [CLR_Time_MicroSec] end ) OVER() * 100.0 AS DECIMAL(5, 2)) AS [CLR_Time_Percent],
       [CPU_Time_Ms],[CPU_Time_Ms]/1000 [CPU_Time_Sec],
       [Duration_MicroSec],[Duration_MicroSec]/1000000 [Duration_Sec]
FROM DB_CPU_Stats
WHERE DatabaseID > 4 -- system databases
AND DatabaseID <> 32767 -- ResourceDB
ORDER BY [Rank_CPU] OPTION (RECOMPILE);

0

CPU 쿼리가 sys.dm_exec_query_stats너무 좋아서 확장했습니다. 여전히 CPU에 의해 순위가 매겨 지지만 더 나은 서버 프로파일을 얻기 위해 다른 총계와 백분율을 추가했습니다. 이것은 Excel로 멋지게 복사되고 백분율 열의 조건부 색상 서식으로 최악의 숫자가 잘 나타납니다. 나는 3 가지 색상으로 'Graded Color Scale'을 사용했다; 높은 값의 경우 장미 색, 중간의 경우 노란색, 낮음의 경우 녹색.

database id 32676내부 SQL 리소스 데이터베이스 인 레이블을 추가했습니다 . 더 나은 사용 시간을 얻기 위해 CPU와 Duration 시간을 Hours로 변환합니다.

WITH DB_CPU_Stats
AS
(
    SELECT DatabaseID, isnull(DB_Name(DatabaseID),case DatabaseID when 32767 then 'Internal ResourceDB' else CONVERT(varchar(255),DatabaseID)end) AS [DatabaseName], 
      SUM(total_worker_time) AS [CPU Time Ms],
      SUM(total_logical_reads)  AS [Logical Reads],
      SUM(total_logical_writes)  AS [Logical Writes],
      SUM(total_logical_reads+total_logical_writes)  AS [Logical IO],
      SUM(total_physical_reads)  AS [Physical Reads],
      SUM(total_elapsed_time)  AS [Duration MicroSec],
      SUM(total_clr_time)  AS [CLR Time MicroSec],
      SUM(total_rows)  AS [Rows Returned],
      SUM(execution_count)  AS [Execution Count],
      count(*) 'Plan Count'

    FROM sys.dm_exec_query_stats AS qs
    CROSS APPLY (
                    SELECT CONVERT(int, value) AS [DatabaseID] 
                  FROM sys.dm_exec_plan_attributes(qs.plan_handle)
                  WHERE attribute = N'dbid') AS F_DB
    GROUP BY DatabaseID
)
SELECT ROW_NUMBER() OVER(ORDER BY [CPU Time Ms] DESC) AS [Rank CPU],
       DatabaseName,
       [CPU Time Hr] = convert(decimal(15,2),([CPU Time Ms]/1000.0)/3600) ,
        CAST([CPU Time Ms] * 1.0 / SUM([CPU Time Ms]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [CPU Percent],
       [Duration Hr] = convert(decimal(15,2),([Duration MicroSec]/1000000.0)/3600) , 
       CAST([Duration MicroSec] * 1.0 / SUM([Duration MicroSec]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Duration Percent],    
       [Logical Reads],
        CAST([Logical Reads] * 1.0 / SUM([Logical Reads]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Logical Reads Percent],      
       [Rows Returned],
        CAST([Rows Returned] * 1.0 / SUM([Rows Returned]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Rows Returned Percent],
       [Reads Per Row Returned] = [Logical Reads]/[Rows Returned],
       [Execution Count],
        CAST([Execution Count] * 1.0 / SUM([Execution Count]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Execution Count Percent],
       [Physical Reads],
       CAST([Physical Reads] * 1.0 / SUM([Physical Reads]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Physcal Reads Percent], 
       [Logical Writes],
        CAST([Logical Writes] * 1.0 / SUM([Logical Writes]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Logical Writes Percent],
       [Logical IO],
        CAST([Logical IO] * 1.0 / SUM([Logical IO]) OVER() * 100.0 AS DECIMAL(5, 2)) AS [Logical IO Percent],
       [CLR Time MicroSec],
       CAST([CLR Time MicroSec] * 1.0 / SUM(case [CLR Time MicroSec] when 0 then 1 else [CLR Time MicroSec] end ) OVER() * 100.0 AS DECIMAL(5, 2)) AS [CLR Time Percent],
       [CPU Time Ms],[CPU Time Ms]/1000 [CPU Time Sec],
       [Duration MicroSec],[Duration MicroSec]/1000000 [Duration Sec]
FROM DB_CPU_Stats
--WHERE DatabaseID > 4 -- system databases
--AND DatabaseID <> 32767 -- ResourceDB
ORDER BY [Rank CPU] OPTION (RECOMPILE);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.