So habe ich die Antwort auf meine Frage verwendet.
Ich bin ein großer Fan von sp_whoisactive. Wenn Sie das nicht haben, hören Sie auf zu lesen; hier herunterladen .
Also habe ich es so eingerichtet, dass alle 10 Minuten ein Schnappschuss erstellt wird, wie folgt:
DROP TABLE dbo.HESPOmonitoring_output
DECLARE @s VARCHAR(MAX)
EXEC sp_WhoIsActive
@output_column_list = '[login_name][dd%][session_id][program%][sql_com%][sql_text][block%][reads][writes][physical_reads][query_plan][used_memory][tempdb%][wait%][start_time][collection_time][host%][additional%]', @get_outer_command=1, @get_additional_info=1,
@return_schema = 1, @get_plans=1,
@schema = @s OUTPUT
SET @s = REPLACE(@s, '<table_name>', 'dbo.HESPOmonitoring_output')
EXEC(@s)
ALTER TABLE dbo.HESPOmonitoring_output ADD HESPOmonitoring_outputID BIGINT IDENTITY(1,1) NOT NULL
go
SET NOCOUNT ON
DECLARE @Started DATETIME=DATEADD(DAY, 3, GETDATE())
WHILE 1 > 0 BEGIN
EXEC sp_WhoIsActive
@output_column_list = '[login_name][dd%][session_id][program%][sql_com%][sql_text][block%][reads][writes][physical_reads][query_plan][used_memory][tempdb%][wait%][start_time][collection_time][host%][additional%]', @get_outer_command=1, @get_additional_info=1,
@get_plans=1,
@destination_table = 'dbo.HESPOmonitoring_output'
WAITFOR DELAY '00:10:00'
IF GETDATE() > @Started BREAK
END
Ich habe es eine Weile laufen lassen (bis zu 3 Tage). Dann konvertiere ich die gesammelten Daten wie folgt:
/* this query turns HESPOmonitoring_output in a table with one row per SQL statement */
Begin TRY
DROP TABLE #hespo
END TRY
BEGIN CATCH
END CATCH
;WITH XMLNAMESPACES
(DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
SELECT top 10000 H.Start_Time, H.session_id, MAX(H.program_name) AS program_name, MAX(CAST(H.sql_command AS VARCHAR(max))) AS sql_command
, MAX(CAST(H.sql_text AS VARCHAR(max))) AS sql_text
, MAX(H.reads) AS reads
, MAX(H.physical_reads) AS physical_reads
, MAX(H.writes) AS writes
, MAX(H.collection_time) AS collection_time
, MAX(DATEDIFF(second, start_time, collection_time)) AS RunTime
, MAX(HESPOmonitoring_outputID) AS MaxHESPOmonitoring_outputID
, MAX(H.blocking_session_id) AS MaxBlocking_session_id
, Min(H.blocking_session_id) AS MinBlocking_session_id
, count_big(*) as RowCnt
, MAX(TRY_CAST(n.value('(@StatementSubTreeCost)[1]', 'VARCHAR(128)') AS DECIMAL(18,3))) AS StatementSubTreeCost
INTO #hespo
FROM dbo.HESPOmonitoring_output H
CROSS APPLY query_plan.nodes('/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple') AS qn(n)
GROUP BY H.Start_Time, H.session_id
Und schließlich erhalte ich eine Liste, aus der hervorgeht, wo die geschätzten Kosten im Vergleich zur Laufzeit gering sind , ohne dass der Job blockiert wird
SELECT top 10000
H.StatementSubTreeCost/NULLIF(H.RunTime, 0) AS Ratio, H.StatementSubTreeCost, H.RunTime, *
FROM #hespo H
WHERE H.MinBlocking_session_id IS NULL
AND H.RunTime>0
AND H.StatementSubTreeCost IS NOT NULL
ORDER BY 1
Es ist eine sehr interessante Liste , aber es kommt mit ein bisschen Lärm. Zunächst habe ich mich dafür entschieden, schnelle kleine Jobs zu ignorieren, die weniger als 10 Minuten dauern, aber diese Grenze hängt von Ihrer Situation ab.
Jetzt ist es viel einfacher, Jobs zu finden, die mit einem schlechten Plan ausgeführt werden.
Vielen Dank für Ihre Hilfe.