2008-08-26 26 views
29

Ist es möglich, eine Aufschlüsselung der CPU-Auslastung von Datenbank zu erhalten?CPU-Auslastung durch Datenbank?

Ich bin ideal für eine Task-Manager-Typ-Schnittstelle für SQL-Server suchen, aber anstatt auf die CPU-Auslastung der einzelnen PID (wie taskmgr) oder jeder SPID (wie spwho2k5), möchte ich die gesamte CPU-Auslastung anzeigen jeder Datenbank. Übernehmen Sie eine einzelne SQL-Instanz.

Ich weiß, dass Tools geschrieben werden können, diese Daten zu sammeln und darüber zu berichten, aber ich frage mich, ob es ein Tool, das ich von denen Datenbanken sehe eine Live-Ansicht kann die meisten auf die sqlservr.exe CPU-Belastung beitragen.

Antwort

81

Sortieren von. Überprüfen Sie diese Abfrage aus:

SELECT total_worker_time/execution_count AS AvgCPU 
, total_worker_time AS TotalCPU 
, total_elapsed_time/execution_count AS AvgDuration 
, total_elapsed_time AS TotalDuration 
, (total_logical_reads+total_physical_reads)/execution_count AS AvgReads 
, (total_logical_reads+total_physical_reads) AS TotalReads 
, execution_count 
, 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 txt 
, query_plan 
FROM sys.dm_exec_query_stats AS qs 
cross apply sys.dm_exec_sql_text(qs.sql_handle) AS st 
cross apply sys.dm_exec_query_plan (qs.plan_handle) AS qp 
ORDER BY 1 DESC 

Dadurch werden Sie die Abfragen in den Plan-Cache in der Reihenfolge, wie viel CPU sie verbraucht haben. Sie können dies wie in einem SQL-Agent-Job in regelmäßigen Abständen ausführen und die Ergebnisse in eine Tabelle einfügen, um sicherzustellen, dass die Daten auch nach Neustarts erhalten bleiben.

Wenn Sie die Ergebnisse lesen, werden Sie wahrscheinlich erkennen, warum wir diese Daten nicht direkt mit einer einzelnen Datenbank korrelieren können. Erstens kann eine einzelne Abfrage auch seine wahren Datenbank Eltern verstecken, indem Tricks wie dies zu tun:

USE msdb 
DECLARE @StringToExecute VARCHAR(1000) 
SET @StringToExecute = 'SELECT * FROM AdventureWorks.dbo.ErrorLog' 
EXEC @StringToExecute 

Die Abfrage in MSDB ausgeführt werden würde, aber es wäre Ergebnisse von Adventure abzufragen. Wo sollten wir den CPU-Verbrauch zuweisen?

Es wird noch schlimmer, wenn Sie:

  • Join zwischen mehreren Datenbanken
  • Führen Sie eine Transaktion in mehreren Datenbanken, und die Verriegelungs Aufwand mehrere Datenbanken
  • Run SQL-Agent-Aufträge in MSDB erstreckt sich über die "Arbeit" in MSDB, aber sichern Sie einzelne Datenbanken

Es geht weiter und weiter. Aus diesem Grund ist es sinnvoll, die Leistung auf Abfrageebene statt auf Datenbankebene abzustimmen.

In SQL Server 2008R2 hat Microsoft Performance Management- und App-Management-Funktionen eingeführt, mit denen wir eine einzelne Datenbank in einem distributierbaren und implementierbaren DAC-Paket verpacken können. Diese Funktionen erleichtern die Verwaltung der Leistung einzelner Datenbanken ihre Anwendungen. Es tut aber immer noch nicht, wonach du suchst.

Für mehr von denen, überprüfen Sie die T-SQL repository at Toad World's SQL Server wiki (formerly at SQLServerPedia).

Aktualisiert am 1/29, um die Gesamtzahl statt der Durchschnittswerte anzugeben.

+1

Verzeihen Sie meine Ignoranz, aber was sind die Einheiten von AvgCPU und AvgDuration? – Portman

+1

Millisekunden für beide - Millisekunden der CPU-Zeit und Millisekunden der Dauer. Sie können unterschiedlich sein, da Abfragen auf E/A, Sperren, Clients usw. warten können. Ich modifiziere die Abfrage, um auch die Gesamtsummen zu erfassen. (Ich wollte Fußpfund sagen, aber ich konnte kein wirkliches Gesicht halten.) –

15

SQL Server (beginnend mit 2000) installiert Leistungsindikatoren (sichtbar aus Systemmonitor oder Perfmon).

Einer der Zähler Kategorien (von SQL Server 2005 installieren, ist :) - SQLServer: Datenbanken

mit einer Instanz für jede Datenbank. Die verfügbaren Zähler bieten jedoch keinen CPU% Utilization-Zähler oder etwas ähnliches, obwohl es einige Ratenzähler gibt, die Sie verwenden könnten, um eine gute Schätzung der CPU zu erhalten. Ein Beispiel wäre, wenn Sie 2 Datenbanken haben und die gemessene Rate 20 Transaktionen/Sek. Für Datenbank A und 80 Trans/Sek. Für Datenbank B beträgt, dann wüssten Sie, dass A ungefähr 20% der gesamten CPU ausmacht B trägt zu anderen 80% bei.

Es gibt hier einige Fehler, da angenommen wird, dass die ganze Arbeit CPU-gebunden ist, was natürlich bei Datenbanken nicht der Fall ist. Aber das wäre ein Anfang, glaube ich.

1

Ich denke, die Antwort auf Ihre Frage ist nein.

Das Problem ist, dass eine Aktivität auf einer Maschine mehrere Datenbanken laden kann. Wenn ich einen Prozess habe, der aus einer Konfigurations-DB liest, in eine Logging-DB einloggt und je nach Typ Transaktionen in verschiedene DBs ein- und ausschiebt, wie partitioniere ich dann die CPU-Auslastung?

Sie könnten die CPU-Auslastung durch die Transaktionslast teilen, aber das ist wiederum eine grobe Metrik, die Sie in die Irre führen könnte. Wie würden Sie beispielsweise den Transport des Transaktionsprotokolls von einem DB auf einen anderen aufteilen? Ist die CPU beim Lesen oder Schreiben belastet?

Sie suchen besser nach der Transaktionsrate für eine Maschine und der CPU-Last, die sie verursacht. Sie können gespeicherte Prozeduren auch profilieren und sehen, ob einige von ihnen übermäßig viel Zeit benötigen. Dies wird jedoch nicht die gewünschte Antwort liefern.

0

Werfen Sie einen Blick auf SQL Sentry. Es tut alles, was Sie brauchen und mehr.

Grüße, Lieven

0

Haben Sie bei SQL Profiler geschaut?

Nehmen Sie die Standard "T-SQL" oder "Stored Procedure" Vorlage, zwicken Sie die Felder nach der Datenbank-ID gruppieren (ich denke, Sie müssen die Nummer verwenden, erhalten Sie nicht den Datenbanknamen, aber es ist leicht zu finden Verwenden Sie exec sp_databases, um die Liste zu erhalten)

Führen Sie dies für eine Weile und Sie erhalten die gesamte CPU-Anzahl/Disk IO/Wait usw. Dies kann Ihnen den Anteil der CPU von jeder Datenbank verwendet.

Wenn Sie das PerfMon-Zähler bei gleichzeitig (log die Daten in eine SQL-Datenbank), und das gleiche für die SQL Profiler (log zur Datenbank) überwachen, Sie kann der Lage sein, die beiden zusammen zu korrelieren.

Trotzdem sollte es Ihnen einen Hinweis geben, welche DB genauer betrachtet werden sollte. Dann machen Sie dasselbe mit dieser Datenbank-ID und suchen Sie nach den teuersten SQL/Stored Procedures.

6

Hier ist eine Abfrage, die die tatsächliche Datenbank zeigt, die hohe Belastung verursacht. Es beruht auf dem Abfragecache, der in Szenarien mit wenig Arbeitsspeicher häufig geleert wird (wodurch die Abfrage weniger nützlich wird).

select dbs.name, cacheobjtype, total_cpu_time, total_execution_count from 
    (select top 10 
     sum(qs.total_worker_time) as total_cpu_time, 
     sum(qs.execution_count) as total_execution_count, 
     count(*) as number_of_statements, 
     qs.plan_handle 
    from 
     sys.dm_exec_query_stats qs 
    group by qs.plan_handle 
    order by sum(qs.total_worker_time) desc 
    ) a 
inner join 
(SELECT plan_handle, pvt.dbid, cacheobjtype 
FROM (
    SELECT plan_handle, epa.attribute, epa.value, cacheobjtype 
    FROM sys.dm_exec_cached_plans 
     OUTER APPLY sys.dm_exec_plan_attributes(plan_handle) AS epa 
    /* WHERE cacheobjtype = 'Compiled Plan' AND objtype = 'adhoc' */) AS ecpa 
PIVOT (MAX(ecpa.value) FOR ecpa.attribute IN ("dbid", "sql_handle")) AS pvt 
) b on a.plan_handle = b.plan_handle 
inner join sys.databases dbs on dbid = dbs.database_id 
0

bitte diese Abfrage überprüfen:

SELECT 
    DB_NAME(st.dbid) AS DatabaseName 
    ,OBJECT_SCHEMA_NAME(st.objectid,dbid) AS SchemaName 
    ,cp.objtype AS ObjectType 
    ,OBJECT_NAME(st.objectid,dbid) AS Objects 
    ,MAX(cp.usecounts)AS Total_Execution_count 
    ,SUM(qs.total_worker_time) AS Total_CPU_Time 
    ,SUM(qs.total_worker_time)/(max(cp.usecounts) * 1.0) AS Avg_CPU_Time 
FROM sys.dm_exec_cached_plans cp 
INNER JOIN sys.dm_exec_query_stats qs 
    ON cp.plan_handle = qs.plan_handle 
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st 
WHERE DB_NAME(st.dbid) IS NOT NULL 
GROUP BY DB_NAME(st.dbid),OBJECT_SCHEMA_NAME(objectid,st.dbid),cp.objtype,OBJECT_NAME(objectid,st.dbid) 
ORDER BY sum(qs.total_worker_time) desc 
1

alle mit oben im Kopf sagte.
Starten mit SQL Server 2012 (möglicherweise 2008?), gibt es Spalte database_id in sys.dm_exec_sessions.
Es gibt uns einfache Berechnung der CPU für jede Datenbank für derzeit verbundenen Sitzungen. Wenn die Sitzung getrennt wurde, sind die Ergebnisse verschwunden.

select session_id, cpu_time, program_name, login_name, database_id 
    from sys.dm_exec_sessions 
where session_id > 50; 

select sum(cpu_time)/1000 as cpu_seconds, database_id 
from sys.dm_exec_sessions 
group by database_id 
order by cpu_seconds desc; 
Verwandte Themen