今天在 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.