2015-03-24 23 views
1

我有一組工作進程(System.Threading.Thread),它們在MSSQL服務器上執行 查詢。在某些情況下(即將長期修復的錯誤)查詢需要很長時間才能執行,並且我被要求爲管理員用戶(此應用程序而不是數據庫管理員)提供一種方式找到並從應用程序中刪除該查詢在dm_exec_requests中標識特定線程的條目

我發現在我的DBMS this post with a SQL query I can use to get a list of open SQL commands,但我似乎無法找到唯一標識一個特定線程的掛起的SqlCommand /交易/連接

背景信息的結果集的任何數據:要使用Visual Studio 2013調查這個可能的解決方案和SSMS,我創建了一個包含一對線程「worker」和「watcher」的類(在VS,.net 4.5中)。 Worker打開一個事務,並在其包裝類中指定一個引用(所以我可以從「watcher」線程的角度來看一個斷點)。然後,它運行一個「模擬長時間運行的查詢」命令,一個WAITFOR ...同時,Watcher睡覺,直到工作人員正在等待長時間運行的查詢完成,然後命中斷點。在這一點上,我切換到SSMS並從上面的鏈接運行查詢的修改版本:

SELECT * FROM sys.dm_exec_requests req CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS sqltext WHERE wait_type = 'WAITFOR' 

然後我回到VS並深入到當地人(其中包括對的SqlTransaction,SqlConnection的情況下,本地引用和「Worker」創建的SqlCommand)試圖找到任何字段的值與SELECT查詢的結果集中的某一列匹配...

以下是將運行這些查詢的類的示例。 (忽略有關連接/事務等任何細節上的挑剔 - 放心,我有我的連接打開和所有的基本的東西是fuctioning)

public class WorkerThreadTest { 
    private SqlTransaction workerTransaction; 
    private SqlConnection workerConnection; 
    private SqlCommand workerCommand; 

    private System.Threading.Thread worker; 
    private System.Threading.Thread watcher; 

    WorkerThreadTest() { 
     worker = new System.Threading.Thread(new System.Threading.ThreadStart(Run)); 
     watcher = new System.Threading.Thread(new System.Threading.ThreadStart(Watch)); 
     worker.Start(); 
     watcher.Start(); 
    } 

    private void Run() { 
     // Paraphrasing here // 
     workerTransaction = new Transaction(foo); 
     workerConnection = new SqlConnection(foo); 

     // Again, paraphrasing: 
     workerCommand = new SqlCommand("WAITFOR DELAY '0:05';", workerConnection, workerTransaction); 
     workerCommand.Execute(foo); // Thread will wait on this line for 5 minutes 
     bool placeBreakPointHere = true; 
    } 

    private void Watch() { 
     System.Threading.Thread.Sleep(foo); // Wait enough time for worker to execute its command 
     bool placeBreakPointHere = true; 
     // Here is where I explore my locals 
    } 
} 


// Inside main program: 
WorkerThreadTest myWorkerThread = new WorkerThreadTest(); 

這裏是一個樣本行從SQL查詢返回的工作線程執行之後在WAITFOR:

session_id request_id start_time status command sql_handle statement_start_offset statement_end_offset plan_handle database_id user_id connection_id blocking_session_id wait_type wait_time last_wait_type wait_resource open_transaction_count open_resultset_count transaction_id context_info percent_complete estimated_completion_time cpu_time total_elapsed_time scheduler_id task_address reads writes logical_reads text_size language date_format date_first quoted_identifier arithabort ansi_null_dflt_on ansi_defaults ansi_warnings ansi_padding ansi_nulls concat_null_yields_null transaction_isolation_level lock_timeout deadlock_priority row_count prev_error nest_level granted_query_memory executing_managed_code group_id query_hash query_plan_hash statement_sql_handle statement_context_id dbid objectid number encrypted text 
112 2 2015-03-24 16:34:12.433 suspended WAITFOR 0x01004300C7A0DC2CB05D23780200000000000000000000000000000000000000000000000000000000000000 118 -1 0x06004300C7A0DC2CF07EA34A0400000001000000000000000000000000000000000000000000000000000000 67 1 9E1EF06D-A755-4EBD-82AA-B030F8B6D19B 0 WAITFOR 72294 WAITFOR  1 1 433172712 0x0000FFFFFFFFFFFFFFFF 0 0 0 72294 4 0x0000000243685468 0 0 0 -1 us_english mdy 7 1 0 1 0 1 1 1 1 2 -1 0 0 0 2 0 0 2 NULL NULL NULL NULL 67 NULL NULL 0 (@ContextInfo varbinary(10))SET CONTEXT_INFO @ContextInfo WAITFOR DELAY '0:05'; 

有沒有什麼辦法可以唯一地標識符合我的工作線程的特定實例的行?

(注:有沒有保證的主機名,IP或查詢的文本將是唯一的)

+0

此外,我不偏向dm_exec_requests,任何識別session_id的方法或任何其他殺死查詢DBMS方法的方法都可以。 – 2015-03-24 22:58:00

回答

2

我會做這樣的事情。

在應用程序中,我將顯示所有查詢的列表,類似於SSMS。如您所知,該列表可以從sys.dm_exec_requests獲得。實際上,我不會顯示所有查詢,但會顯示運行時間超過某個閾值(使用start_time)的那些查詢,即那些可能應該停止的查詢。

應用程序將通過其會話ID對kill任何查詢執行命令。

我沒有看到需要找到運行應該被終止的查詢的應用程序的其餘部分中的特定線程。只要查詢被終止,線程的Execute很可能會拋出一些異常。相應地抓住並處理它。長時間運行的查詢可能已由另一臺客戶端計算機上的另一個應用程序實例啓動,因此有關客戶端線程的任何信息都是無用的。

因此,最終用戶會看到服務器上已經運行了很長時間的所有查詢的列表,可以看到他們到目前爲止運行了多久,並且可以終止任何此類查詢。

爲什麼這種方法不適合你?

+0

感謝您的建議 - 此解決方案無效的原因是我們無法將定義置於「太長」 - 在某些情況下,報告可能需要很長時間(我們將處理與「大數據」一起,以及年終流程)。因此,殺死報告的決定必須留給用戶。此外,還有多個安全配置文件正在播放,因此一個用戶可能無法看到其他用戶或組運行的查詢。因此,我們需要向用戶顯示一個列表,其中只包括他/她可以修改的線程,然後允許他/她自行決定取消。 – 2015-03-25 13:55:27

+0

因此,這意味着您需要以某種方式過濾「sys.dm_exec_requests」的輸出。不過,你不需要識別特定的線程。你只需要弄清楚用戶有權殺死哪些查詢。您可以從查看'HostName'和'Login'開始,僅向用戶顯示源自他的計算機和他的登錄信息的查詢。不過,主要想法是,你殺死查詢,而不是線程,當查詢被終止時,線程將自行死亡。 – 2015-03-25 22:40:05

+1

另外,您已經知道您可以使用'sys.dm_exec_sql_text'來檢索正在運行的查詢的文本,因此您可以在查詢文本中包含一些內容以幫助您確定需要的內容,例如報告名稱或線程ID,或用戶ID。以一種不影響查詢本身的方式。我會嘗試將這些信息添加到查詢文本的註釋中,或者額外的'PRINT'語句或存儲過程的額外參數中,並通過'sys.dm_exec_sql_text'檢查它是否可見。 – 2015-03-25 22:46:35