it-swarm.com.de

Wie erhalte ich die CPU-Auslastung nach Datenbank für eine bestimmte Instanz?

Ich habe die folgenden Abfragen gefunden, um die CPU-Auslastung nach Datenbank zu ermitteln, aber sie zeigen unterschiedliche Ergebnisse:

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);

Die obige Abfrage zeigt, dass das Problem bei einer meiner Datenbanken liegt (fast 96%).

Die folgende Abfrage zeigt, dass das Problem beim Master und bei den Verteilungsdatenbanken liegt (ca. 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

Ich habe das sys.sysprocesses wird misshandelt. Bedeutet dies, dass die Ergebnisse der zweiten Abfrage falsch sind?

15
gotqn

Obwohl ich, wie @Thomas, @Aaron in den Kommentaren zu der Frage, ob die CPU-Auslastung pro Datenbank entweder korrekt oder nützlich ist, voll und ganz zustimme, kann ich zumindest die Frage beantworten, warum diese beiden Fragen so sind anders. Und der Grund, warum sie unterschiedlich sind, zeigt an, welches genauer ist, obwohl dieses höhere Maß an Genauigkeit immer noch relativ zu demjenigen ist, das spezifisch ungenau ist, daher immer noch nicht wirklich genau ;-).

Die erste Abfrage verwendet sys.dm_exec_query_stats , um CPU-Informationen abzurufen (d. H. total_worker_time). Wenn Sie zu der verlinkten Seite gehen, die die MSDN-Dokumentation für diese DMV ist, sehen Sie ein kurzes Intro mit 3 Sätzen und 2 dieser Sätze geben uns das meiste, was wir brauchen, um den Kontext dieser Informationen zu verstehen ("wie zuverlässig ist es"). und "wie ist es mit sys.sysprocesses zu vergleichen"). Diese beiden Sätze sind:

Gibt aggregierte Leistungsstatistiken für zwischengespeicherte Abfragepläne in SQL Server zurück. ... Wenn ein Plan aus dem Cache entfernt wird, werden die entsprechenden Zeilen aus dieser Ansicht entfernt

Der erste Satz, "Gibt aggregierte Leistungsstatistiken zurück", besagt, dass die Informationen in dieser DMV (genau wie in mehreren anderen) kumulativ und nicht nur spezifisch sind Abfragen, die gerade ausgeführt werden. Dies wird auch durch ein Feld in dieser DMV angezeigt, das nicht Teil der Abfrage in der Frage execution_count Ist, was wiederum zeigt, dass es sich um kumulative Daten handelt. Und es ist sehr praktisch, wenn diese Daten kumulativ sind, da Sie Durchschnittswerte usw. erhalten können, indem Sie einige der Metriken durch execution_count Teilen.

Der zweite Satz, "Pläne, die aus dem Cache entfernt werden, werden ebenfalls aus dieser DMV entfernt", zeigt an, dass es sich überhaupt nicht um ein vollständiges Bild handelt, insbesondere wenn der Server bereits über einen ziemlich vollständigen Plan-Cache verfügt und unter Last steht und daher Pläne abläuft etwas häufig. Außerdem werden die meisten DMVs beim Zurücksetzen des Servers zurückgesetzt, sodass sie keinen echten Verlauf darstellen, selbst wenn diese Zeilen nach Ablauf der Pläne nicht entfernt wurden.

Vergleichen wir nun das Obige mit sys.sysprocesses. Diese Systemansicht zeigt nur, was gerade ausgeführt wird, genau wie die Kombination von sys.dm_exec_connections , sys.dm_exec_sessions und sys.dm_exec_requests ( Dies ist auf der verlinkten Seite für sys.dm_exec_sessions angegeben. Dies ist eine völlig andere Ansicht des Servers als die DMV sys.dm_exec_query_stats, Die die Daten auch nach Abschluss des Vorgangs enthält. Das heißt, in Bezug auf "Sind die Ergebnisse der zweiten Abfrage falsch?" Frage, sie sind nicht falsch, sie beziehen sich nur auf einen anderen Aspekt (d. h. Zeitrahmen) der Leistungsstatistiken.

Die Abfrage mit sys.sysprocesses Betrachtet also nur "gerade jetzt". Und die Abfrage mit sys.dm_exec_query_stats Betrachtet meistens (vielleicht), was seit dem letzten Neustart des SQL Server-Dienstes (oder offensichtlich dem Neustart des Systems) passiert ist. Für die allgemeine Leistungsanalyse scheint sys.dm_exec_query_stats Weitaus besser zu sein, aber auch hier werden ständig nützliche Informationen gelöscht. In beiden Fällen müssen Sie auch die Punkte berücksichtigen, die @Aaron in den (seitdem entfernten) Fragekommentaren zur Genauigkeit des Werts "database_id" gemacht hat (dh nur die aktive Datenbank, die den Code initiiert hat) , nicht unbedingt dort, wo das "Problem" auftritt).

Wenn Sie jedoch nur einen Eindruck davon bekommen möchten/wollen, was gerade in allen Datenbanken passiert, möglicherweise weil sich die Dinge gerade verlangsamen, ist es besser, die Kombination aus sys.dm_exec_connections, sys.dm_exec_sessions und sys.dm_exec_requests (und nicht das veraltete sys.sysprocesses). Denken Sie daran, dass Sie nach Abfragen suchen, nicht nach Datenbanken, da Abfragen mehrere Datenbanken umfassen können, einschließlich UDFs aus einer oder mehreren Datenbanken. usw.


BEARBEITEN:
] ist isoliert und gehört einem anderen Kunden).

Die folgende Abfrage hilft bei der Identifizierung von Abfragen mit einer hohen durchschnittlichen CPU-Auslastung. Die Daten in der DMV query_stats werden komprimiert, da diese Datensätze dieselbe Abfrage (ja, dieselbe Teilmenge des Abfragebatches) mehrmals mit jeweils einem anderen Ausführungsplan anzeigen können.

;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;
14
Solomon Rutzky

Ich habe die Abfrage für die Division durch 0 Fehler angepasst und die Spaltennamen für das Kopieren/Einfügen in Excel optimiert.

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);
1
HakanM

Ich mochte die CPU-Abfrage von sys.dm_exec_query_stats so sehr, dass ich es erweitert habe. Es ist immer noch nach CPU geordnet, aber ich habe andere Summen und Prozentsätze hinzugefügt, um ein besseres Serverprofil zu erhalten. Dies lässt sich gut in Excel kopieren und mit der bedingten Farbformatierung in den Prozentspalten fallen die schlechtesten Zahlen gut auf. Ich habe die 'Graded Color Scale' mit 3 Farben verwendet. eine rosafarbene Farbe für hohe Werte, gelb für mittlere, grün für niedrige.

Ich habe ein Label für database id 32676 Dies ist die interne SQL-Ressourcendatenbank. Ich konvertiere die CPU- und Dauerzeit in Stunden, um ein besseres Gefühl für die Zeitnutzung zu bekommen.

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);
0
Drew Neff