У SQL Server існує спосіб визначення значень параметрів, переданих виконуваній збереженій процедурі


13

Один із способів визначення виконуваної збереженої процедури - це використання методів "динамічного управління", наприклад:

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

Однак це відображає лише текст оператора створення збереженої процедури. наприклад:

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

В ідеалі я хотів би побачити, які параметри були для запущеної процедури, які змушують її працювати так довго для певного набору параметрів порушення.

Чи є спосіб це зробити? (У цьому питанні Аарон Бертран згадує DBCC InputBuffer , але я не думаю, що це підходить для цієї проблеми.)


Дійсно єдиний спосіб зафіксувати вхідні параметри або побачити, що було передано під час виконання, - це записувати значення та виклик у файл журналу. Це можна легко зробити за допомогою RAISEERROR, якщо ви хочете побачити його в журналі помилок або, доклавши трохи більше зусиль, запишіть його у зовнішній файл кудись.
Стів Манґямелі

Відповіді:


16

Ця інформація - значення параметрів часу виконання, передані в процедуру збереження (тобто виклик RPC) або параметризований запит - доступна лише через SQL Trace (і я припускаю, що еквівалентна розширена подія в нових версіях SQL Server). Ви можете побачити це, запустивши SQL Server Profiler (поставляється з SQL Server) і вибору різних «Completed» події, такі як: RPC:Completed, SP:Completed, і SQL:BatchCompleted. Вам також потрібно вибрати поле "TextData", оскільки значення будуть там.

Різниця між моєю відповіддю і @ Kin в відповідь на це питання полягає в тому , що @ відповідь Kin в (якщо я не помиляюся, в цьому випадку я видалю це) фокусується на тому , як:

  • власний план запитів (у цьому випадку він може містити інформацію про параметр часу виконання, але не для інших сесій / SPID), або
  • плани з DMV (у цьому випадку вони повинні мати лише складені значення параметрів, які не є значеннями виконання).

Моя відповідь зосереджена на отриманні значень параметрів для інших сеансів, які зараз запущені. Покладаючись на DMV, немає ніякого способу дізнатися, чи значення параметра виконання є таким же, як зібране значення параметра. І контекст цього питання полягає у відстеженні значення виконання запитів, що надсилаються через інші сесії / SPID (і в SQL Server 2005, тоді як розширені події були представлені в SQL Server 2008).


13

Ви можете увімкнути фактичний план виконання, а потім переглянути XML-план виконання.

введіть тут опис зображення

Або ви можете використовувати інструмент плану дослідник SQL годинного і побачити parametersвкладку, перерахують compiled valueі run time valueдля фактичного виконання плану.

Якщо ви не можете ввімкнути фактичний план, тоді ви можете переглянути кеш плану, як описано нижче.

-- 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
Кеш плану має лише складені значення, а не значення для певного запуску пізніше. Можна також використовувати Showplan XML Statistics Profileподію в Profiler, щоб отримати фактичний план, хоча, якщо прокрутити Profiler, існували б менш інтенсивні способи отримати це.
Мартін Сміт

1

@SolomonRutzky має рацію.
SQL Profiler Trace - єдиний спосіб ( без редагування Sproc ).

Редагуйте свою Sproc:

Однак наступне найкраще - трохи відредагувати відповідний Sproc.
Оголосіть змінну DateTime на початку з поточного часу.
В кінці Sproc запишіть значення таблиці Sproc_StartTime, Sproc_EndTime та параметрів у таблицю.

Ви можете навіть додати деяку умовну логіку, щоб використовувати DateDiff () лише для ведення журналів, коли в обробці Sproc було використано тривалий час.
Це може пришвидшити ваш Sproc та зменшити споживання місця вашої таблиці журналів, коли Sproc працює на вершині.

Тоді у вас є файл журналу, який ви можете запитувати та аналізувати протягом місяців (без сліду, що працює в Prod).
Закінчивши налаштування свого Sproc, просто видаліть кілька доданих вами рядків логіки Timer і Logger.

Значення параметрів кешованого плану:

Слід зазначити, що включення в параметр "Текучий керований план" параметрів у вашій таблиці журналів може допомогти вам визначити, чи вони ускладнюють проблему продуктивності .
Я використовую, OPTIMIZE FORщоб встановити, як обробляти параметри в моєму Sproc, коли я знаю, що він буде використовуватися для нарізки та виправлення даних.
Я вважаю, що використання OPTIMIZE FORрезультатів і послідовних і швидких результатів при використанні того ж Sproc з параметрами, як і додаткові фільтри .
Це, безумовно, одна менша змінна, яку слід врахувати, якщо вказати, як з ними поводитися.

Нижче наведено приклад того, що ви можете додати до нижньої частини своєї Select-Statement:

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

Я помітив, використовуючи запит Ерланда Соммарського для подрібнення XML плану та витягування ParameterCompiledValue, що перша "база даних" CTE не враховує плани, які мають ПОПЕРЕДЖЕННЯ (наприклад, неявні перетворення), оскільки CHARINDEX (вбудована функція) шукає перший рядок відповідності виразів input (тобто) та такі попередження використовують ці самі фрази / вузли.

Тому я пропоную замінити цей розділ переглянутим розділом нижче:

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

Переглянений розділ:

       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.
Метт

-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
Відповіді лише на коди відмовляють. Розглянемо додавання пояснення, чому цей код вирішує проблему. Дивіться, як відповісти
Пітер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.