今天在 troubleshooting 客戶主機上問題的時候,不經意從 Tcpview 發現某個系統在使用者使用的時候會對 SQL Server 產生大量 TIME_WAIT session,這對於自我要求的系統開發者來說,是個不能視而不見的瑕疵,於是開始進行 debug...
經過兩個小時分析後,發現了一個狀況(先看以下程式碼):
'// 預設 Conn 已經建立 '// 第一個 adCmdStoreProc Dim rs1 : Set rs1 = Server.CreateObject("ADODB.Recordset") Dim cmd1 : Set cmd1 = Server.CreateObject("ADODB.Command") cmd1.ActiveConnection = Conn cmd1.CommandText = "usp_SPNAME1" cmd1.CommandType = adCmdStoredProc cmd1.Parameters.Refresh cmd1.Parameters("@Param1").Value = 1 Set rs1 = cmd1.Execute '// 第二個 adCmdStoreProc Dim rs2 : Set rs2 = Server.CreateObject("ADODB.Recordset") Dim cmd2 : Set cmd2 = Server.CreateObject("ADODB.Command") cmd2.ActiveConnection = Conn cmd2.CommandText = "usp_SPNAME2" cmd2.CommandType = adCmdStoredProc cmd2.Parameters.Refresh cmd2.Parameters("@Param2").Value = 2 Do While NOT rs1.EOF cmd2.Execute rs1.MoveNext Loop
這是一個 loop 但是為巢狀查詢,依據 rs1 取得的 recordset 執行 cmd2 的查詢,以上程式碼看起來沒有問題,執行起來也不會發生錯誤,但是會產生等同於 recordset count 數量的 TCP TIME_WAIT session,關鍵在於 Conn (Connection) 被拿來用了兩次 (cmd1.ActiveConnection & cmd2.ActiveConnection),即便在第二次設定給 cmd2前 Set cmd1 = Nothing 也沒用,一樣會造成 cmd2 在作動時產生 TIME_WAIT 。 (CommandType = adCmdStoredProc 時在設定Parameters 值的時候就會產生 TIME_WAIT,CommandType = adCmdText 時在 Execute 時會產生 TIME_WAIT)
而這個 issue 的解決辦法是:
每個 ActiveConnection 都給他一個獨立的 Connection object
延伸閱讀:
Nested RecordSet and the port/socket in TIME_WAIT problem by example.