วิธีรับการใช้งาน 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 เห็นด้วยอย่างสมบูรณ์กับ @Aaron ในความคิดเห็นเกี่ยวกับคำถามเกี่ยวกับ "การใช้งาน CPU ต่อฐานข้อมูล" อย่างถูกต้องหรือมีประโยชน์ฉันอย่างน้อยสามารถตอบคำถามว่าทำไมทั้งสองข้อจึงเป็นเช่นนั้น ต่าง และสาเหตุที่ทำให้พวกเขาแตกต่างกันจะระบุว่าอันใดที่ถูกต้องมากกว่าถึงแม้ว่าความแม่นยำระดับสูงจะยังคงสัมพันธ์กับสิ่งที่ไม่ถูกต้องโดยเฉพาะดังนั้นจึงยังไม่แม่นยำ ;-)

แบบสอบถามแรกใช้sys.dm_exec_query_statsเพื่อรับข้อมูล CPU (เช่นtotal_worker_time) หากคุณไปที่หน้าที่เชื่อมโยงซึ่งเป็นเอกสาร MSDN สำหรับ DMV นั้นคุณจะเห็นคำนำประโยคสั้น ๆ 3 ประโยคและประโยคที่ 2 ของประโยคเหล่านี้ให้สิ่งที่เราต้องเข้าใจบริบทของข้อมูลนี้ ("ความน่าเชื่อถือ") และ "มันเปรียบเทียบกับsys.sysprocesses" อย่างไร ประโยคทั้งสองนั้นคือ:

ส่งคืนสถิติประสิทธิภาพโดยรวมสำหรับแผนการสืบค้นที่แคชใน SQL Server ... เมื่อแผนถูกลบออกจากแคชแถวที่เกี่ยวข้องจะถูกลบออกจากมุมมองนี้

ประโยคแรก "ส่งคืนสถิติประสิทธิภาพโดยรวม " บอกเราว่าข้อมูลใน DMV นี้ (เหมือนกับคนอื่น ๆ หลายคน) นั้นเป็นข้อมูลสะสมและไม่เฉพาะเจาะจงกับแบบสอบถามที่กำลังทำงานอยู่เท่านั้น นอกจากนี้ยังระบุด้วยเขตข้อมูลใน DMV นั้นที่ไม่ได้เป็นส่วนหนึ่งของแบบสอบถามในคำถามexecution_countซึ่งแสดงให้เห็นอีกครั้งว่านี่เป็นข้อมูลสะสม และมันก็เป็นประโยชน์มากที่จะมีข้อมูลเหล่านี้จะสะสมในขณะที่คุณจะได้รับค่าเฉลี่ย ฯลฯ execution_countโดยการหารบางส่วนของตัวชี้วัดโดย

ประโยคที่สอง "แผนที่ถูกลบออกจากแคชก็ถูกลบออกจาก DMV นี้ด้วย" แสดงว่ามันไม่ได้เป็นภาพที่สมบูรณ์เลยโดยเฉพาะอย่างยิ่งถ้าเซิร์ฟเวอร์มีแคชแผนที่ค่อนข้างสมบูรณ์อยู่แล้วและอยู่ภายใต้ภาระและด้วยเหตุนี้แผนการหมดอายุ ค่อนข้างบ่อย นอกจากนี้ DMV ส่วนใหญ่จะถูกรีเซ็ตเมื่อเซิร์ฟเวอร์รีเซ็ตดังนั้นจึงไม่ใช่ประวัติจริงแม้ว่าแถวเหล่านี้จะไม่ถูกลบออกเมื่อแผนหมดอายุ

sys.sysprocessesตอนนี้ให้ความคมชัดของข้างต้นด้วย มุมมองระบบนี้แสดงเฉพาะสิ่งที่กำลังทำงานอยู่เช่นเดียวกับการรวมกันของsys.dm_exec_connections , sys.dm_exec_sessionsและsys.dm_exec_requests (ซึ่งระบุไว้ในหน้าเชื่อมโยงสำหรับsys.dm_exec_sessions) นี่เป็นมุมมองที่แตกต่างอย่างสิ้นเชิงของเซิร์ฟเวอร์เมื่อเปรียบเทียบกับsys.dm_exec_query_statsDMV ซึ่งเก็บข้อมูลแม้หลังจากกระบวนการเสร็จสิ้น ความหมายเกี่ยวข้องกับ "ผลลัพธ์จากแบบสอบถามที่สองผิดหรือไม่" คำถามพวกเขาไม่ผิดพวกเขาเกี่ยวข้องกับแง่มุมที่แตกต่างกัน (เช่นกรอบเวลา) ของสถิติประสิทธิภาพ

ดังนั้นการใช้แบบสอบถามsys.sysprocessesจึงดูที่ "ตอนนี้" เท่านั้น และการสืบค้นที่ใช้sys.dm_exec_query_statsนั้นส่วนใหญ่ (อาจ) สิ่งที่เกิดขึ้นตั้งแต่การรีสตาร์ทครั้งล่าสุดของบริการ SQL Server (หรือการรีบูตระบบ) สำหรับการวิเคราะห์ประสิทธิภาพโดยทั่วไปดูเหมือนว่าsys.dm_exec_query_statsจะดีกว่ามาก แต่ก็มีข้อมูลที่มีประโยชน์อยู่ตลอดเวลา และในทั้งสองกรณีคุณต้องพิจารณาจุดที่ @Aaron ทำไว้ในความคิดเห็นของคำถาม (ตั้งแต่ลบออก) เกี่ยวกับความถูกต้องของค่า "database_id" ในตอนแรก (เช่นจะแสดงเฉพาะฐานข้อมูลที่แอ็คทีฟที่เริ่มต้นโค้ด ไม่จำเป็นว่าจะเกิด "ปัญหา" ที่ใด)

แต่ถ้าคุณเพียงแค่ต้อง / ต้องการที่จะรับความรู้สึกของสิ่งที่เกิดขึ้นในขณะนี้ทั่วทั้งฐานข้อมูลทั้งหมดอาจจะเป็นเพราะสิ่งที่จะชะลอตัวลงในขณะนี้คุณจะดีกว่าใช้การรวมกันของ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 รายงานใน microseconds ( แต่ที่ถูกต้องมิลลิวินาที) ที่ได้รับการบริโภคโดยการประหารชีวิตของแผนนี้ตั้งแต่มันถูกรวบรวม. " มันช่วยได้ไหม สามารถแปลงเป็นมิลลิวินาทีได้อย่างง่ายดายหากนั่นคือสิ่งที่คุณต้องการดู
โซโลมอน Rutzky

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 และด้วยการจัดรูปแบบสีตามเงื่อนไขในคอลัมน์ Percent ตัวเลขที่เลวร้ายที่สุดนั้นโดดเด่น ฉันใช้ 'เกล็ดสีระดับ' ด้วย 3 สี; สีกุหลาบสำหรับค่าสูงเหลืองสำหรับกลางสีเขียวสำหรับต่ำ

ฉันเพิ่มเลเบลdatabase id 32676ซึ่งเป็นฐานข้อมูลทรัพยากร SQL ภายใน ฉันแปลงเวลา CPU และระยะเวลาเป็นชั่วโมงเพื่อให้ได้ความรู้สึกที่ดีขึ้นเกี่ยวกับการใช้เวลา

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.