Dalam SQL Server, apakah ada cara untuk menentukan nilai parameter yang diteruskan ke prosedur tersimpan yang dijalankan


13

Salah satu cara untuk menentukan mengeksekusi prosedur tersimpan adalah dengan menggunakan metode "manajemen dinamis", seperti:

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

Namun, ini hanya menampilkan teks dari pernyataan membuat prosedur tersimpan. misalnya:

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

Idealnya saya ingin melihat parameter apa yang digunakan untuk menjalankan prosedur yang menyebabkannya berjalan sangat lama untuk set parameter tertentu yang menyinggung.

Apakah ada cara untuk melakukan itu? (Dalam pertanyaan ini Aaron Bertrand menyebutkan DBCC InputBuffer , tapi saya pikir itu tidak sesuai untuk masalah ini.)


Sungguh satu-satunya cara untuk menangkap parameter input atau melihat apa yang diteruskan pada saat run time adalah dengan mencatat nilai dan panggilan ke file log. Anda dapat melakukan ini dengan mudah dengan RAISEERROR jika Anda ingin melihatnya di log kesalahan atau dengan sedikit usaha, tuliskan ke file eksternal di suatu tempat.
Steve Mangiameli

Jawaban:


16

Informasi ini - nilai parameter run-time diteruskan ke Stored Procedure (yaitu panggilan RPC) atau kueri parameterisasi - hanya tersedia melalui SQL Trace (dan saya mengasumsikan Extended Event yang setara dalam versi SQL Server yang lebih baru). Anda dapat melihat ini dengan menjalankan SQL Server Profiler (datang dengan SQL Server) dan memilih berbagai "Selesai" acara, seperti: RPC:Completed, SP:Completed, dan SQL:BatchCompleted. Anda juga perlu memilih bidang "TextData" karena nilainya ada di sana.

Perbedaan antara jawaban saya dan @ Kin jawaban atas pertanyaan ini adalah bahwa jawaban @ Kin (kecuali saya salah, dalam hal ini saya akan menghapus ini) berfokus pada mendapatkan baik:

  • rencana kueri Anda sendiri (dalam hal ini dapat memiliki info parameter runtime di dalamnya, tetapi tidak untuk Sesi / SPID lain), atau
  • rencana dari DMV (dalam hal ini mereka hanya harus memiliki nilai parameter yang dikompilasi, yang bukan nilai runtime).

Jawaban saya berfokus pada mendapatkan nilai parameter untuk sesi lain yang sedang berjalan. Ketika mengandalkan DMV, tidak ada cara untuk mengetahui apakah nilai parameter runtime sama dengan nilai parameter yang dikompilasi. Dan konteks pertanyaan ini adalah melacak nilai runtime kueri yang diajukan melalui Sesi / SPID lain (dan dalam SQL Server 2005, sedangkan Peristiwa Diperpanjang diperkenalkan dalam SQL Server 2008).


13

Anda dapat mengaktifkan paket eksekusi aktual dan kemudian melihat XML rencana eksekusi.

masukkan deskripsi gambar di sini

Atau Anda dapat menggunakan alat explorer plan sql sentry dan melihat parameterstab yang akan mencantumkan compiled valuedan run time valueuntuk rencana eksekusi aktual.

Jika Anda tidak dapat mengaktifkan paket yang sebenarnya maka Anda dapat melihat ke dalam cache rencana seperti yang dijelaskan di bawah ini.

-- 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
Cache paket hanya memiliki nilai yang dikompilasi daripada nilai untuk menjalankan tertentu nanti. Bisa juga menggunakan Showplan XML Statistics Profileevent di Profiler untuk mendapatkan rencana yang sebenarnya meskipun jika mengeset Profiler akan ada cara yang kurang intensif untuk mendapatkan ini.
Martin Smith

1

@SolomonRutzky benar.
SQL Profiler Trace adalah satu-satunya cara ( tanpa mengedit Sproc ).

Edit Sproc Anda:

Namun , hal terbaik berikutnya adalah sedikit mengedit Sproc yang dimaksud.
Nyatakan variabel DateTime di awal dengan Waktu Saat Ini.
Di Akhir Sproc, Log Nilai Sproc_StartTime, Sproc_EndTime, dan Parameter ke Tabel.

Anda bahkan dapat menambahkan beberapa logika kondisional untuk menggunakan DateDiff () hanya untuk mencatat ketika waktu yang lama digunakan dalam memproses Sproc.
Ini dapat Mempercepat Sproc Anda dan mengurangi Konsumsi Ruang dari Tabel Log Anda ketika Sproc menjalankan tip-top.

Kemudian Anda memiliki File Log yang dapat Anda query dan analisis selama berbulan-bulan (tanpa Trace berjalan di Prod).
Ketika Anda selesai menyetel Sproc Anda, hapus saja beberapa baris Timer dan Logger logic yang Anda tambahkan.

Nilai Parameter Rencana-Cached:

Saya harus menyebutkan bahwa memasukkan Nilai Parameter Cached-Plan Saat Ini di Tabel Log Anda dapat membantu Anda menentukan apakah mereka menambah masalah kinerja .
Saya menggunakan OPTIMIZE FORuntuk mengatur bagaimana menangani Parameter di Sproc saya ketika saya tahu itu akan digunakan untuk mengiris dan mencelupkan data.
Saya menemukan bahwa menggunakan OPTIMIZE FORhasil yang konsisten dan cepat saat menggunakan Sproc yang sama dengan Parameter sebagai Filter Opsional .
Ini jelas salah satu variabel yang kurang dipertimbangkan jika Anda menentukan cara menanganinya.

Di bawah ini adalah contoh dari apa yang Anda tambahkan ke bagian bawah Pernyataan-Pilih Anda:

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

Saya perhatikan ketika menggunakan permintaan Erland Sommarskog untuk merobek XML rencana dan mengeluarkan ParameterCompiledValue bahwa CTE "baseata" pertama tidak memperhitungkan rencana yang memiliki PERINGATAN (mis. Konversi implisit) sebagai CHARINDEX (fungsi ) mencari string pencocokan ekspresi pertama input (yaitu) dan peringatan tersebut menggunakan frase / node yang sama.

Karena itu saya mengusulkan mengganti bagian ini dengan bagian yang direvisi di bawah ini:

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

Bagian yang direvisi:

       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
Kode hanya jawaban yang tidak disarankan. Pertimbangkan untuk menambahkan penjelasan mengapa kode ini memecahkan masalah. Lihat Cara Menjawab
Peter Vandivier
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.