Une façon de déterminer la procédure stockée en cours d'exécution est d'utiliser des méthodes de "gestion dynamique", comme ceci:
SELECT
sqlText.Text, req.*
FROM
sys.dm_exec_requests req
OUTER APPLY
sys.dm_exec_sql_text(req.sql_handle) AS sqltext
Toutefois, cela affiche uniquement le texte de l'instruction create de la procédure stockée. par exemple.:
CREATE PROCEDURE IMaProcedure @id int AS SELECT * FROM AllTheThings Where id = @id
Idéalement, j'aimerais voir quels étaient les paramètres de la procédure en cours d'exécution qui la font fonctionner si longtemps pour l'ensemble particulier de paramètres incriminés.
Y-a-t-il un moyen de faire ça? (Dans cette questionAaron Bertrand mentionne DBCC InputBuffer , mais je ne pense pas que ce soit approprié pour ce problème.)
Ces informations - les valeurs des paramètres d'exécution passées dans une procédure stockée (c'est-à-dire un appel RPC) ou une requête paramétrée - sont uniquement disponibles via une trace SQL (et je suppose que l'événement étendu équivalent dans les versions plus récentes de SQL Server). Vous pouvez le voir en exécutant SQL Server Profiler (il est fourni avec SQL Server) et en sélectionnant les divers événements "Terminés", tels que: RPC:Completed
, SP:Completed
, et SQL:BatchCompleted
. Vous devez également sélectionner le champ "TextData" car les valeurs y seront.
La différence entre ma réponse et @ Kin's réponse sur cette question est que la réponse de @ Kin (à moins que je ne me trompe, auquel cas je supprimerai cela) se concentre sur l'obtention soit:
Ma réponse se concentre sur l'obtention des valeurs des paramètres pour autre sessions en cours d'exécution. Lorsque vous vous appuyez sur les DMV, il n'y a aucun moyen de savoir si la valeur du paramètre d'exécution est la même que la valeur du paramètre compilé. Et le contexte de cette question est de rechercher la valeur d'exécution des requêtes soumises via d'autres sessions/SPID (et dans SQL Server 2005, tandis que les événements étendus ont été introduits dans SQL Server 2008).
Vous pouvez activer le plan d'exécution réel, puis consulter le XML du plan d'exécution.
Ou vous pouvez utiliser outil Explorateur de plans de sentinelle sql et voir l'onglet parameters
qui listera les compiled value
et run time value
pour le plan d'exécution réel.
Si vous ne pouvez pas activer le plan réel, vous pouvez consulter le cache du plan comme décrit ci-dessous.
-- 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
@SolomonRutzky a raison.
La trace du profileur SQL est le seul moyen ( sans modifier le Sproc ).
Cependant , la meilleure chose à faire est de modifier légèrement le Sproc en question.
Déclarez une variable DateTime au début avec l'heure actuelle.
À la fin du Sproc, connectez les valeurs Sproc_StartTime, Sproc_EndTime et Parameter à une table.
Vous pouvez même ajouter une logique conditionnelle pour utiliser un DateDiff () pour la journalisation uniquement lorsqu'une période de temps étendue a été utilisée dans le traitement du Sproc.
Cela peut accélérer votre Sproc et réduire la consommation d'espace de votre table de journal lorsque le Sproc est en cours d'exécution.
Ensuite, vous avez un fichier journal que vous pouvez interroger et analyser au cours des mois (sans trace en cours d'exécution dans Prod).
Lorsque vous avez terminé le réglage de votre Sproc, supprimez simplement les quelques lignes de logique Timer et Logger que vous avez ajoutées.
Je dois mentionner que l'inclusion des valeurs actuelles des paramètres du plan mis en cache dans votre table de journal peut vous aider à déterminer si elles aggravent le problème de performances .
J'utilise OPTIMIZE FOR
pour définir comment gérer les paramètres dans mon Sproc quand je sais qu'il sera utilisé pour le découpage et le découpage des données.
Je trouve qu'en utilisant OPTIMIZE FOR
donne des résultats cohérents et rapides lors de l'utilisation du même Sproc avec des paramètres comme Filtres optionnels.
C'est certainement une variable de moins à considérer si vous spécifiez comment les gérer.
Vous trouverez ci-dessous un exemple de ce que vous pourriez ajouter au bas de votre instruction Select:
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))
J'ai remarqué lors de l'utilisation de la requête d'Erland Sommarskog pour déchiqueter le plan XML et extraire ParameterCompiledValue que le premier CTE "basedata" ne tient pas compte des plans qui ont AVERTISSEMENTS (par exemple implicite conversions) car CHARINDEX (fonction intégrée) recherche la première expression correspondant à l'entrée de chaîne (c'est-à-dire) et ces avertissements utilisent ces mêmes phrases/nœuds.
Je propose donc de remplacer cette section par la section révisée ci-dessous:
CHARINDEX('<ParameterList>', qp.query_plan) + LEN('<ParameterList>') AS paramstart,
CHARINDEX('</ParameterList>', qp.query_plan) AS paramend
Section révisée:
CHARINDEX('<ParameterList><ColumnReference', qp.query_plan) + LEN('<ParameterList>') AS paramstart,
CHARINDEX('</ParameterList></QueryPlan>', qp.query_plan) AS paramend