ใน 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

เป็นการดีที่ฉันต้องการดูว่าพารามิเตอร์สำหรับกระบวนการทำงานที่ทำให้มันทำงานนานมากสำหรับชุดของพารามิเตอร์ที่ละเมิด

มีวิธีทำเช่นนั้นหรือไม่? (ในคำถามนี้ Aaron Bertrandกล่าวถึงInputBuffer DBCCแต่ฉันไม่คิดว่ามันเหมาะสมสำหรับปัญหานี้)


จริงๆวิธีเดียวที่จะจับพารามิเตอร์การป้อนข้อมูลหรือดูสิ่งที่ถูกส่งผ่านในเวลาทำงานคือการบันทึกค่าและการโทรไปยังไฟล์บันทึก คุณสามารถทำสิ่งนี้ได้อย่างง่ายดายด้วย RAISEERROR หากคุณต้องการดูในบันทึกข้อผิดพลาดหรือใช้ความพยายามเพิ่มขึ้นเล็กน้อยเขียนมันลงในไฟล์ภายนอก
Steve Mangiameli

คำตอบ:


16

ข้อมูลนี้ - ค่าพารามิเตอร์รันไทม์ที่ส่งผ่านไปยังโพรซีเดอร์ Stored (เช่นการเรียก RPC) หรือเคียวรีที่กำหนดพารามิเตอร์ - สามารถใช้ได้ผ่าน SQL Trace เท่านั้น (และฉันถือว่า Extended Event ที่เทียบเท่าใน SQL Server เวอร์ชันใหม่กว่า) คุณสามารถดูนี้โดยใช้ SQL Server Profiler (มันมาพร้อมกับ SQL Server) และเลือกต่างๆ "เสร็จสมบูรณ์" เหตุการณ์เช่นRPC:Completed, และSP:Completed SQL:BatchCompletedคุณต้องเลือกฟิลด์ "TextData" เนื่องจากค่าจะอยู่ในนั้น

ความแตกต่างระหว่างคำตอบของฉันและ @ ญาติของคำตอบในคำถามนี้คือคำตอบ @ ญาติของ (ถ้าผมเข้าใจผิดซึ่งในกรณีนี้ผมจะลบ) มุ่งเน้นไปที่การได้รับอย่างใดอย่างหนึ่ง

  • แผนคิวรีของคุณเอง (ซึ่งในกรณีนี้สามารถมีข้อมูลพารามิเตอร์รันไทม์ได้ แต่ไม่ใช่สำหรับเซสชันอื่น ๆ / SPID) หรือ
  • แผนจาก DMVs (ซึ่งในกรณีนี้ควรมีเฉพาะค่าพารามิเตอร์ที่รวบรวมซึ่งไม่ใช่ค่ารันไทม์)

คำตอบของฉันมุ่งเน้นไปที่การรับค่าพารามิเตอร์สำหรับเซสชันอื่นที่กำลังทำงานอยู่ เมื่อพึ่งพา DMVs จะไม่มีทางทราบว่าค่าพารามิเตอร์รันไทม์นั้นเหมือนกับค่าพารามิเตอร์ที่คอมไพล์แล้วหรือไม่ และบริบทของคำถามนี้คือการติดตามค่ารันไทม์ของแบบสอบถามที่ส่งผ่านเซสชัน / SPID อื่น ๆ (และใน SQL Server 2005 ในขณะที่มีการขยายเหตุการณ์ใน SQL Server 2008)


13

คุณสามารถเปิดแผนการดำเนินการจริงจากนั้นดู XML แผนการดำเนินการ

ป้อนคำอธิบายรูปภาพที่นี่

หรือคุณสามารถใช้เครื่องมือสำรวจแผนของ sql sentryและดู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 เพื่อรับแผนจริงแม้ว่าการใช้ Wheeler ออก Profiler จะมีวิธีการที่เข้มข้นน้อยกว่า
Martin Smith

1

@SolomonRutzky ถูกต้อง
SQL Profiler Trace เป็นวิธีเดียว ( โดยไม่ต้องแก้ไข Sproc )

แก้ไข Sproc ของคุณ:

อย่างไรก็ตามสิ่งที่ดีที่สุดถัดไปคือการแก้ไข Sproc ที่มีปัญหาเล็กน้อย
ประกาศตัวแปร DateTime ที่เริ่มต้นด้วยเวลาปัจจุบัน
ในตอนท้ายของ Sproc ให้บันทึก Sproc_StartTime, Sproc_EndTime และค่าพารามิเตอร์ไปยังตาราง

คุณสามารถเพิ่มตรรกะเงื่อนไขบางอย่างเพื่อใช้ DateDiff () สำหรับการบันทึกเท่านั้นเมื่อใช้ระยะเวลานานในการประมวลผล Sproc
สิ่งนี้อาจเร่งความเร็ว Sproc ของคุณและลดการใช้พื้นที่ของ Log Log ของคุณเมื่อ Sproc กำลังทำงานอยู่ด้านบนสุด

จากนั้นคุณมีไฟล์บันทึกคุณสามารถสืบค้นและวิเคราะห์ในช่วงหลายเดือนที่ผ่านมา (โดยไม่ต้องมีร่องรอยการทำงานใน Prod)
เมื่อคุณปรับแต่ง Sproc ของคุณเสร็จแล้วให้ลบตรรกะตัวจับเวลาและตัวบันทึกที่คุณเพิ่มเข้าไป

ค่าพารามิเตอร์ของแผนแคช

ฉันควรพูดถึงว่ารวมถึงค่าพารามิเตอร์แผนแคชปัจจุบันในตารางบันทึกของคุณอาจช่วยให้คุณตรวจสอบว่าพวกเขาจะรวมปัญหาประสิทธิภาพการทำงาน
ฉันใช้OPTIMIZE FORเพื่อตั้งค่าวิธีการจัดการพารามิเตอร์ใน Sproc ของฉันเมื่อฉันรู้ว่ามันจะถูกใช้สำหรับการแบ่งและการทำข้อมูล
ฉันพบว่าการใช้OPTIMIZE FORอัตราผลตอบแทนที่สอดคล้องกันและผลลัพธ์ที่รวดเร็วเมื่อใช้ SProc เดียวกันกับค่าพารามิเตอร์ที่เป็นตัวกรองเป็นตัวเลือก
มันเป็นตัวแปรที่น้อยกว่าที่จะพิจารณาหากคุณระบุวิธีจัดการกับมัน

ด้านล่างเป็นตัวอย่างของสิ่งที่คุณอาจเพิ่มไว้ที่ด้านล่างของคำชี้แจงการเลือกของคุณ:

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

ฉันสังเกตว่าเมื่อใช้แบบสอบถามของ Erland Sommarskog เพื่อฉีกแผน XML และดึง ParameterCompiledValue ว่า CTE "basedata" ตัวแรกไม่ได้พิจารณาแผนที่มีคำเตือน (เช่นการแปลงโดยนัย) เป็น CHARINDEX (ฟังก์ชันในตัว) มองหาสตริงที่ตรงกับนิพจน์แรก อินพุต (เช่น) และคำเตือนดังกล่าวใช้วลี / โหนดเดียวกันเหล่านี้

ฉันจึงเสนอให้แทนที่ส่วนนี้ด้วยส่วนที่แก้ไขด้านล่าง:

      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.
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
คำตอบของรหัสเท่านั้นที่จะหมดกำลังใจ ลองเพิ่มคำอธิบายว่าทำไมรหัสนี้จึงแก้ปัญหาได้ ดูวิธีการตอบ
Peter Vandivier
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.