Gibt es in SQL Server eine Möglichkeit, die Werte der Parameter zu bestimmen, die an eine ausgeführte gespeicherte Prozedur übergeben werden


13

Eine Möglichkeit, die auszuführende gespeicherte Prozedur zu bestimmen, besteht in der Verwendung von "dynamischen Verwaltungsmethoden" wie folgt:

SELECT 
    sqlText.Text, req.* 
FROM 
    sys.dm_exec_requests req
OUTER APPLY 
    sys.dm_exec_sql_text(req.sql_handle) AS sqltext

Dies zeigt jedoch nur den Text der create-Anweisung der gespeicherten Prozedur an. z.B:

CREATE PROCEDURE IMaProcedure @id int AS SELECT * FROM AllTheThings Where id = @id

Im Idealfall würde ich gerne sehen, welche Parameter für die ausgeführte Prozedur dafür verantwortlich sind, dass sie für den jeweiligen Satz an fehlerhaften Parametern so lange ausgeführt wird.

Gibt es eine Möglichkeit, das zu tun? (In dieser Frage Aaron Bertrand erwähnt DBCC Inputbuffer , aber ich glaube nicht , dass für dieses Problem geeignet ist.)


Die einzige Möglichkeit, die Eingabeparameter zu erfassen oder zu sehen, was zur Laufzeit übergeben wurde, besteht darin, die Werte und den Aufruf in einer Protokolldatei zu protokollieren. Mit RAISEERROR können Sie dies ganz einfach tun, wenn Sie es im Fehlerprotokoll anzeigen möchten, oder es mit etwas mehr Aufwand in eine externe Datei schreiben.
Steve Mangiameli

Antworten:


16

Diese Informationen - Laufzeitparameterwerte, die an eine gespeicherte Prozedur (dh einen RPC-Aufruf) oder eine parametrisierte Abfrage übergeben werden - sind nur über eine SQL-Ablaufverfolgung verfügbar (und ich nehme das entsprechende erweiterte Ereignis in den neueren Versionen von SQL Server an). Sie können dies sehen von SQL Server Profiler ausgeführt wird (es kommt mit SQL Server) und die verschiedenen „Completed“ Events auswählen, wie zum Beispiel: RPC:Completed, SP:Completed, undSQL:BatchCompleted . Sie müssen auch das Feld "TextData" auswählen, da sich die Werte dort befinden.

Der Unterschied zwischen meiner Antwort und der Antwort von @ Kin auf diese Frage besteht darin, dass sich die Antwort von @ Kin darauf konzentriert, entweder

  • Ihren eigenen Abfrageplan (in diesem Fall kann er die Laufzeitparameterinformationen enthalten, jedoch nicht für andere Sitzungen / SPIDs) oder
  • Pläne aus den DMVs (in diesem Fall sollten sie nur die kompilierten Parameterwerte haben, die keine Laufzeitwerte sind).

Meine Antwort konzentriert sich auf das Abrufen der Parameterwerte für andere Sitzungen, die derzeit ausgeführt werden. Wenn Sie sich auf die DMVs verlassen, können Sie nicht feststellen, ob der Laufzeitparameterwert mit dem kompilierten Parameterwert übereinstimmt. Im Kontext dieser Frage wird der Laufzeitwert von Abfragen ermittelt, die über andere Sitzungen / SPIDs gesendet werden (und in SQL Server 2005, während Extended Events in SQL Server 2008 eingeführt wurden).


13

Sie können den tatsächlichen Ausführungsplan aktivieren und dann das XML des Ausführungsplans anzeigen.

Bildbeschreibung hier eingeben

Oder Sie können verwenden SQL Sentry Plan Explorer - Tool und die sehen parametersRegisterkarte , dass die Liste wird compiled valueundrun time value für den tatsächlichen Ausführungsplan.

Wenn Sie nicht können auf dem tatsächlichen Plan drehen , dann können Sie in Plan - Cache aussehen wie unten beschrieben.

-- borrowed from  Erland Sommarskog
-- Link : http://www.sommarskog.se/query-plan-mysteries.html#dmvgettingplans
-- Remember that you are looking at the estimated plan so the actual no. of rows and actual executions wont be there ! <-- Important why a particular plan is bad.

DECLARE @dbname    nvarchar(256),
        @procname  nvarchar(256)
SELECT @dbname = 'Northwind',  -- Your DB name
       @procname = 'dbo.List_orders_11' -- The SP that you want to get parameters for !

; WITH basedata AS (
   SELECT qs.statement_start_offset/2 AS stmt_start,
          qs.statement_end_offset/2 AS stmt_end,
          est.encrypted AS isencrypted, est.text AS sqltext,
          epa.value AS set_options, qp.query_plan,
          charindex('<ParameterList>', qp.query_plan) + len('<ParameterList>')
             AS paramstart,
          charindex('</ParameterList>', qp.query_plan) AS paramend
   FROM   sys.dm_exec_query_stats qs
   CROSS  APPLY sys.dm_exec_sql_text(qs.sql_handle) est
   CROSS  APPLY sys.dm_exec_text_query_plan(qs.plan_handle,
                                            qs.statement_start_offset,
                                            qs.statement_end_offset) qp
   CROSS  APPLY sys.dm_exec_plan_attributes(qs.plan_handle) epa
   WHERE  est.objectid  = object_id (@procname)
     AND  est.dbid      = db_id(@dbname)
     AND  epa.attribute = 'set_options'
), next_level AS (
   SELECT stmt_start, set_options, query_plan,
          CASE WHEN isencrypted = 1 THEN '-- ENCRYPTED'
               WHEN stmt_start >= 0
               THEN substring(sqltext, stmt_start + 1,
                              CASE stmt_end
                                   WHEN 0 THEN datalength(sqltext)
                                   ELSE stmt_end - stmt_start + 1
                              END)
          END AS Statement,
          CASE WHEN paramend > paramstart
               THEN CAST (substring(query_plan, paramstart,
                                   paramend - paramstart) AS xml)
          END AS params
   FROM   basedata
)
SELECT set_options AS [SET], n.stmt_start AS Pos, n.Statement,
       CR.c.value('@Column', 'nvarchar(128)') AS Parameter,
       CR.c.value('@ParameterCompiledValue', 'nvarchar(128)') AS [Sniffed Value],
       CAST (query_plan AS xml) AS [Query plan]
FROM   next_level n
CROSS  APPLY   n.params.nodes('ColumnReference') AS CR(c)
ORDER  BY n.set_options, n.stmt_start, Parameter

5
Der Plan-Cache enthält nur die kompilierten Werte und nicht die Werte für einen bestimmten späteren Durchlauf. Showplan XML Statistics ProfileEvent in Profiler könnte auch verwendet werden , um den aktuellen Plan abzurufen. Wenn Sie Profiler jedoch entfernen, gibt es weniger intensive Möglichkeiten, dies zu erreichen.
Martin Smith

1

@SolomonRutzky ist richtig.
SQL Profiler Trace ist der einzige Weg ( ohne das Sproc zu bearbeiten) ).

Bearbeiten Sie Ihren Sproc:

Das nächstbeste ist jedoch, den betreffenden Sproc leicht zu bearbeiten.
Deklarieren Sie eine DateTime-Variable am Anfang mit der aktuellen Uhrzeit.
Protokollieren Sie am Ende des Sprocs die Werte für Sproc_StartTime, Sproc_EndTime und Parameter in einer Tabelle.

Sie können sogar eine Bedingungslogik hinzufügen, um ein DateDiff () nur für die Protokollierung zu verwenden, wenn bei der Verarbeitung des Sproc eine längere Zeit verwendet wurde.
Dies kann Ihren Sproc beschleunigen und den Platzverbrauch Ihrer Protokolltabelle verringern, wenn der Sproc "tip-top" ausgeführt wird.

Dann haben Sie eine Protokolldatei, die Sie über Monate abfragen und analysieren können (ohne dass ein Trace in Prod ausgeführt wird).
Wenn Sie mit der Optimierung Ihres Sproc fertig sind, löschen Sie einfach die wenigen Zeilen der Timer- und Logger-Logik, die Sie hinzugefügt haben.

Parameterwerte für den zwischengespeicherten Plan:

Ich sollte erwähnen, dass das Einbeziehen der Werte der aktuellen Cache-Plan-Parameter in Ihre Protokolltabelle Ihnen dabei helfen kann, festzustellen, ob sie das Leistungsproblem verschlimmern .
Ich verwende OPTIMIZE FORdiese Option, um festzulegen, wie Parameter in meinem Sproc behandelt werden sollen, wenn ich weiß, dass sie zum Schneiden und Zerteilen von Daten verwendet werden.
Ich finde, dass die Verwendung von OPTIMIZE FORErgebnissen konsistent und schnell ist, wenn derselbe Sproc mit Parametern als optionale Filter verwendet wird .
Es ist definitiv eine Variable weniger zu berücksichtigen, wenn Sie angeben, wie damit umgegangen werden soll.

Nachfolgend finden Sie ein Beispiel dafür, was Sie am Ende Ihrer Select-Anweisung hinzufügen könnten:

OPTION(OPTIMIZE FOR (@SiteID = 'ABC',
                     @LocationID = NULL, @DepartmentID = NULL,
                     @EmployeeID = NULL, @CustomerID = NULL,
                     @ProductID = NULL, @OrderID = NULL, @OrderStatusID = NULL,
                     @IncludedCancelledOrders = 1,
                     @StartDate UNKNOWN, @EndDate UNKNOWN))

0

Bei der Verwendung der Abfrage von Erland Sommarskog zum Zerkleinern von Plan-XML und zum Herausziehen von ParameterCompiledValue ist mir aufgefallen, dass der erste CTE für "basedata" keine Pläne mit WARNUNGEN (z. B. implizite Konvertierungen) berücksichtigt, da der CHARINDEX (integrierte Funktion) nach der ersten Ausdrucksübereinstimmungszeichenfolge sucht Eingabe (dh) und solche Warnungen verwenden dieselben Phrasen / Knoten.

Ich schlage daher vor, diesen Abschnitt durch den überarbeiteten Abschnitt zu ersetzen:

      CHARINDEX('<ParameterList>', qp.query_plan) + LEN('<ParameterList>') AS paramstart,
      CHARINDEX('</ParameterList>', qp.query_plan) AS paramend

Überarbeiteter Abschnitt:

       CHARINDEX('<ParameterList><ColumnReference', qp.query_plan) + LEN('<ParameterList>') AS paramstart,
       CHARINDEX('</ParameterList></QueryPlan>', qp.query_plan) AS paramend

Disallowed implicit conversion from data type xml to data type varchar, table 'sys.dm_exec_query_plan', column 'query_plan'. Use the CONVERT function to run this query.
Matt

-1
SELECT DB_NAME(req.database_id),
sqltext.TEXT,
req.session_id,
req.status,
req.start_time,
req.command,
req.cpu_time,
req.total_elapsed_time ,   REPLACE(REPLACE(REPLACE(REPLACE(
CONVERT(VARCHAR(MAX), CONVERT(XML, REPLACE( query_plan, 'xmlns="','xmlns1="')).query('//        ParameterList/ColumnReference')),
'<ColumnReference Column="','declare '),
'" ParameterDataType="',' '),
'" ParameterCompiledValue="(',' = '),
')"/>', CONCAT(';', CHAR(10) , CHAR(13))) ParameterList
FROM sys.dm_exec_requests req
CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS sqltext 
 CROSS  APPLY sys.dm_exec_text_query_plan(plan_handle, statement_start_offset, statement_end_offset) qp
order by req.total_elapsed_time desc 

2
Antworten nur mit Code werden nicht empfohlen. Erwägen Sie, eine Erklärung hinzuzufügen, warum dieser Code ein Problem löst. Siehe Antwort
Peter Vandivier
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.