如何從DUMP中查找SQL Connection相關數據


問題

現在大多數的Web 應用都需要連接到數據庫, 對數據庫的數據進行操作. 有些時候Web應用對數據庫的數據進行操作時, 會發生一些性能問題. 這個時候如果能找到一些有用的數據, 對性能調優是非常有用的. 例如 SQL Connection, Connection String, SQL Command Text. 本文將介紹如何從DUMP中找到這些數據.
以下是我們的示例代碼. 這是非常且簡單的步驟. 打開一個連接, 執行一條語句.

public void ExecuteReader()
        {
            String connectionString = @"Database=MyDataBaseMASTER;Server=MyTestServer;UID=myUID20130531;Min Pool Size=5;Max Pool Size=100;Connect Timeout=100;Password=Password!01";

            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                String commandText = "sp_MySqlProcedure";
                conn.Open();

                using (SqlCommand  sqlCommand = new SqlCommand(commandText,conn))
                {
                    sqlCommand.CommandType = CommandType.StoredProcedure;
                    using (IDataReader reader = sqlCommand.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            // do something
                        }
                    }
                }
            }
        }

場景: 有一個頁面調用到了這個ExecuteReader Method. 但是頁面一直白屏, 沒有任何的反應. 在問題發生的時候, 抓了一個DUMP.現在我們並不清楚發生問題的SQL語句是什么, 也不知道這個Web應用的連接字符串是什么. Connection Pool是不是已經滿了. 我們期望從DUMP里面看出一些線索.

步驟

1. 首先我們需要加載SOS.DLL. 實例應用為64-bit, .net framework 2.0, SOS.dll 的路徑為C:\Windows\Microsoft.NET\Framework64\v2.0.50727\SOS.dll

0:087> .load C:\Windows\Microsoft.NET\Framework64\v2.0.50727\sos.dll

2. 找到發生問題的線程, 執行!clrstack可以檢查CLR 的CALLSTACK. 這個線程當前已經將請求發送到了數據庫, 正在做數據讀取的動作. 是什么原因導致這個線程一直處於讀取狀態?
我們下一步希望從這個DUMP中知道所執行的SQL 語句以及SQL Connection方面的信息。

0:087> !clrstack
OS Thread Id: 0x2a3c (87)
Child-SP         RetAddr          Call Site
0000000020b3d1e0 000007fee09e0b5b SNINativeMethodWrapper.SNIReadSync(System.Runtime.InteropServices.SafeHandle, IntPtr ByRef, Int32)
0000000020b3d2e0 000007fee09e09fa System.Data.SqlClient.TdsParserStateObject.ReadSni(System.Data.Common.DbAsyncResult, System.Data.SqlClient.TdsParserStateObject)
0000000020b3d380 000007fee09e2efe System.Data.SqlClient.TdsParserStateObject.ReadNetworkPacket()
0000000020b3d3e0 000007fee09e2ecc System.Data.SqlClient.TdsParserStateObject.ReadBuffer()
0000000020b3d410 000007fee09e2924 System.Data.SqlClient.TdsParserStateObject.ReadByte()
0000000020b3d440 000007fee09d7b4a System.Data.SqlClient.TdsParser.Run(System.Data.SqlClient.RunBehavior, System.Data.SqlClient.SqlCommand, System.Data.SqlClient.SqlDataReader, System.Data.SqlClient.BulkCopySimpleResultSet, System.Data.SqlClient.TdsParserStateObject)
0000000020b3d510 000007fee09d7410 System.Data.SqlClient.SqlDataReader.ConsumeMetaData()
0000000020b3d560 000007fee09d43c9 System.Data.SqlClient.SqlDataReader.get_MetaData()
0000000020b3d5e0 000007fee09d42ad System.Data.SqlClient.SqlCommand.FinishExecuteReader(System.Data.SqlClient.SqlDataReader, System.Data.SqlClient.RunBehavior, System.String)
0000000020b3d660 000007fee09d3d48 System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(System.Data.CommandBehavior, System.Data.SqlClient.RunBehavior, Boolean, Boolean)
0000000020b3d740 000007fee09d3b8c System.Data.SqlClient.SqlCommand.RunExecuteReader(System.Data.CommandBehavior, System.Data.SqlClient.RunBehavior, Boolean, System.String, System.Data.Common.DbAsyncResult)
0000000020b3d7f0 000007fee09d39c3 System.Data.SqlClient.SqlCommand.RunExecuteReader(System.Data.CommandBehavior, System.Data.SqlClient.RunBehavior, Boolean, System.String)
0000000020b3d830 000007fee09d37b3 System.Data.SqlClient.SqlCommand.ExecuteReader(System.Data.CommandBehavior, System.String)
0000000020b3d8e0 000007ff004cedf1 System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(System.Data.CommandBehavior)
0000000020b3e0a0 000007fef60432b3 ASP.mytestpage_aspx.btnExecute_Click(System.Object, System.EventArgs)
0000000020b3e130 000007fef6042ecc System.Web.UI.WebControls.Button.OnClick(System.EventArgs)
0000000020b3e170 000007fef57e207d System.Web.UI.WebControls.Button.RaisePostBackEvent(System.String)
0000000020b3e1c0 000007fef57fb475 System.Web.UI.Page.RaisePostBackEvent(System.Web.UI.IPostBackEventHandler, System.String)
0000000020b3e1f0 000007fef57fa750 System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
0000000020b3e2c0 000007fef57fa67b System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
0000000020b3e320 000007fef57fa610 System.Web.UI.Page.ProcessRequest()
0000000020b3e380 000007ff023fb639 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
0000000020b3e3e0 000007fef5801ab7 ASP.mytestpage_aspx.ProcessRequest(System.Web.HttpContext)

3. 由於這個線程與SQL COMMAND的執行有關. 執行!dso命令, 從heap中找到SqlCommand對象. 並且對這個對象進行檢查.

0:087> !dso
OS Thread Id: 0x2a3c (87)
RSP/REG          Object           Name
0000000020b3d178 00000001cfc81600 System.Data.SqlClient.SqlCommand

0:087> !do 00000001cfc81600 
Name: System.Data.SqlClient.SqlCommand
MethodTable: 000007fee0a2d180
EEClass: 000007fee0896478
Size: 224(0xe0) bytes
 (C:\Windows\assembly\GAC_64\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fef72573f8  400018a        8        System.Object  0 instance 0000000000000000 __identity
000007fef66b9ba8  40008e0       10 ...ponentModel.ISite  0 instance 0000000000000000 site
000007fef66e94a0  40008e1       18 ....EventHandlerList  0 instance 0000000000000000 events
000007fef72573f8  40008df      208        System.Object  0   shared           static EventDisposed
                                 >> Domain:Value  0000000002384230:NotInit  000000000245bf00:000000019f8ae5c0 <<
000007fef725ed78  40016f3       b0         System.Int32  1 instance          9892277 ObjectID
000007fef7257b08  40016f4       20        System.String  0 instance 00000001200c00c0 _commandText
000007fee0a2e7f8  40016f5       b4         System.Int32  1 instance                4 _commandType

0:087> !do 00000001200c00c0 
Name: System.String
MethodTable: 000007fef7257b08
EEClass: 000007fef6e5e550
Size: 56(0x38) bytes
 (C:\Windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: sp_MySqlProcedure

從SqlCommand對象, 我們可以看到_commandText里面的值是”sp_MySqlProcedure”. 這正是我們示例代碼里面所付的值” String commandText = "sp_MySqlProcedure";”. 那么 我們怎么確定Command的類型? 我們在代碼中定義的是” sqlCommand.CommandType = CommandType.StoredProcedure;”.

使用ILSpy反編譯SqlCommand的代碼. 可以確認CommandType會被賦值給_commandType. 這是一個enum. StoreProcedure的值為4.

4. 要找到ConnectionString. 首先需要需要先找到SqlConnection對象. 回到剛才的SqlCommand對象. 里面有個field “_activeConnection”. 這是當前的Connection.

0:087> !do 00000001cfc81600 
Name: System.Data.SqlClient.SqlCommand
MethodTable: 000007fee0a2d180
EEClass: 000007fee0896478
Size: 224(0xe0) bytes
 (C:\Windows\assembly\GAC_64\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
…..
000007fee0a2cad0  40016fe       38 ...ent.SqlConnection  0 instance 00000001cfc818e0 _activeConnection 0:087> !do 00000001cfc818e0 
Name: System.Data.SqlClient.SqlConnection
MethodTable: 000007fee0a2cad0
EEClass: 000007fee08963c0
Size: 104(0x68) bytes
 (C:\Windows\assembly\GAC_64\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fef72573f8  400018a        8        System.Object  0 instance 0000000000000000 __identity
000007fef66b9ba8  40008e0       10 ...ponentModel.ISite  0 instance 0000000000000000 site
000007fef66e94a0  40008e1       18 ....EventHandlerList  0 instance 0000000000000000 events
000007fef72573f8  40008df      208        System.Object  0   shared           static EventDisposed
                                 >> Domain:Value  0000000002384230:NotInit  000000000245bf00:000000019f8ae5c0 <<
000007fee0f42ca0  4000be5       20 ...hangeEventHandler  0 instance 0000000000000000 _stateChangeEventHandler
000007fee0f543a0  400172c       28 ...t.SqlDebugContext  0 instance 0000000000000000 _sdc
000007fef7256cd8  400172d       58       System.Boolean  1 instance                0 _AsycCommandInProgress
000007fee0a33528  400172e       30 ...ent.SqlStatistics  0 instance 0000000000000000 _statistics
000007fef7256cd8  400172f       59       System.Boolean  1 instance                0 _collectstats
000007fef7256cd8  4001730       5a       System.Boolean  1 instance                0 _fireInfoMessageEventOnUserErrors
000007fee0a305c0  4001733       38 ...ConnectionOptions  0 instance 000000019f8cae50 _userConnectionOptions
000007fee0a2fcd0  4001734       40 ...nnectionPoolGroup  0 instance 000000019f8cb720 _poolGroup

通過ILSpy來檢查SQLCommand的代碼. SQLConnection對象是復制給它的property : Connection. 在這個Property的get中, 該值賦給了_activeConnection. 這是我們從_activeConnection中找SQLConnection的原因.

5. SQL Connection的對象是從SQL Connection Pool里面取到. 連接池使新連接必須打開的次數得以減少. Pooler 保持物理連接的所有權. 通過為每個給定的連接配置保留一組活動連接來管理連接. 每當用戶在連接上調用Open時, 池進程就會查找池中可用的連接。  如果某個池連接可用,會將該連接返回給調用者,而不是打開新連接。  應用程序在該連接上調用 Close 時, 池進程會將連接返回到活動連接池集中, 而不是關閉連接. 連接返回到池中之后, 即可在下一個 Open 調用中重復使用.

只有配置相同的連接可以建立池連接. ADO.NET 同時保留多個池, 每種配置各一個. 在使用集成的安全性時, 連接按照連接字符串以及 Windows 標識分到多個池中.

請參考 : http://msdn.microsoft.com/zh-cn/library/8xx3tyca.aspx

6. 從SQL Connection中找到連接字符串, 必須先找到ConnectionPoolOption對象. 從代碼中能看到來自於_userConnectionOptions. ConnectionString保存在_usersConnectionString中.

0:087> !do 00000001cfc818e0 
Name: System.Data.SqlClient.SqlConnection
MethodTable: 000007fee0a2cad0
EEClass: 000007fee08963c0
Size: 104(0x68) bytes
 (C:\Windows\assembly\GAC_64\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fef72573f8  400018a        8        System.Object  0 instance 0000000000000000 __identity
000007fef66b9ba8  40008e0       10 ...ponentModel.ISite  0 instance 0000000000000000 site
000007fef66e94a0  40008e1       18 ....EventHandlerList  0 instance 0000000000000000 events
000007fef72573f8  40008df      208        System.Object  0   shared           static EventDisposed
                                 >> Domain:Value  0000000002384230:NotInit  000000000245bf00:000000019f8ae5c0 <<
000007fee0f42ca0  4000be5       20 ...hangeEventHandler  0 instance 0000000000000000 _stateChangeEventHandler
000007fee0f543a0  400172c       28 ...t.SqlDebugContext  0 instance 0000000000000000 _sdc
000007fef7256cd8  400172d       58       System.Boolean  1 instance                0 _AsycCommandInProgress
000007fee0a33528  400172e       30 ...ent.SqlStatistics  0 instance 0000000000000000 _statistics
000007fef7256cd8  400172f       59       System.Boolean  1 instance                0 _collectstats
000007fef7256cd8  4001730       5a       System.Boolean  1 instance                0 _fireInfoMessageEventOnUserErrors
000007fee0a305c0  4001733       38 ...ConnectionOptions  0 instance 000000019f8cae50 _userConnectionOptions


0:087> !do 000000019f8cae50 
Name: System.Data.SqlClient.SqlConnectionString
MethodTable: 000007fee0a304c0
EEClass: 000007fee08babc0
Size: 184(0xb8) bytes
 (C:\Windows\assembly\GAC_64\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fef7257b08  4000bef        8        System.String  0 instance 000000019f840ba8 _usersConnectionString

0:087> !do 000000019f840ba8 
Name: System.String
MethodTable: 000007fef7257b08
EEClass: 000007fef6e5e550
Size: 308(0x134) bytes
 (C:\Windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: Database=MyDataBaseMASTER;Server=MyTestServer;UID=myUID20130531;Min Pool Size=5;Max Pool Size=100;Connect Timeout=100;Password=Password!01

從ILSpy中檢查SQLConnection.ConnectionString這個屬性.  通過這個屬性, 我們能在應用中取得ConnectionString. 而ConnectionString實際是來源與_userConnectionOptions(ConnectionPoolOption類型) 保存在中的_usersConnectionString (String 類型)

7. “既然Connection是從ConnectionPool里分配出來, 我們是否能從DUMP中看到當前已經分配的Connection數目?” 有些情況下, 程序員沒有在使用完Connection之后, 顯示的關閉Connection. 這些Connection或一直active直到TimeOut才會回到ConnectionPool中等待重用. 所以, 有些場合中, 我們也需要從DUMP中檢查ConnectionPool已經分配了多少Connection.
首先需要從SqlConnection對象中找到_innerConeection. 再找到 _connectionPool. _connectionPool中有一個_totalObjects, 記錄了分配了多少Connection. 如果這個值跟MaxConnection相等, ConnectionPool就不會再分配新的Connection.

0:087> !do 00000001cfc818e0 
Name: System.Data.SqlClient.SqlConnection
MethodTable: 000007fee0a2cad0
EEClass: 000007fee08963c0
Size: 104(0x68) bytes
 (C:\Windows\assembly\GAC_64\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fef72573f8  400018a        8        System.Object  0 instance 0000000000000000 __identity
000007fef66b9ba8  40008e0       10 ...ponentModel.ISite  0 instance 0000000000000000 site
_userConnectionOptions
000007fee0a2fcd0  4001734       40 ...nnectionPoolGroup  0 instance 000000019f8cb720 _poolGroup
000007fee0a30808  4001735       48 ...onnectionInternal  0 instance 00000001ab87b918 _innerConnection

0:087> !do 00000001ab87b918 
Name: System.Data.SqlClient.SqlInternalConnectionTds
MethodTable: 000007fee0a33e18
EEClass: 000007fee08bc040
Size: 248(0xf8) bytes
 (C:\Windows\assembly\GAC_64\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fef725ed78  4000f8a       38         System.Int32  1 instance              283 _objectID
000007fef7256cd8  4000f8d       44       System.Boolean  1 instance                0 _allowSetConnectionString
000007fef7256cd8  4000f8e       45       System.Boolean  1 instance                1 _hidePassword
000007fee0a38500  4000f8f       3c         System.Int32  1 instance                1 _state
000007fef724f020  4000f90        8 System.WeakReference  0 instance 00000001ab87ba10 _owningObject
000007fee0a30808  4000f91       10 ...onnectionInternal  0 instance 0000000000000000 _nextPooledObject
000007fee0a2ff20  4000f92       18 ....DbConnectionPool  0 instance 000000019f8cc558 _connectionPool

0:087> !do 000000019f8cc558 
Name: System.Data.ProviderBase.DbConnectionPool
MethodTable: 000007fee0a2ff20
EEClass: 000007fee0897080
Size: 176(0xb0) bytes
 (C:\Windows\assembly\GAC_64\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fef725ed78  400153c       88         System.Int32  1 instance           190000 _cleanupWait
000007fee0a337c8  400153d        8 ...ctionPoolIdentity  0 instance 000000019f8cc4d8 _identity
000007fee0a2f9c8  400153e       10 ...ConnectionFactory  0 instance 000000019f8ba208 _connectionFactory
000007fee0a2fcd0  400153f       18 ...nnectionPoolGroup  0 instance 000000019f8cb720 _connectionPoolGroup
000007fee0a30a58  4001540       20 ...nPoolGroupOptions  0 instance 000000019f8cb6f8 _connectionPoolGroupOptions
000007fee0f52588  4001541       28 ...nPoolProviderInfo  0 instance 0000000000000000 _connectionPoolProviderInfo
000007fee0f1ed90  4001542       8c         System.Int32  1 instance                1 _state
000007fee0a338a8  4001543       30 ...InternalListStack  0 instance 000000019f8cc7c8 _stackOld
000007fee0a338a8  4001544       38 ...InternalListStack  0 instance 000000019f8cc7e0 _stackNew
000007fef7246130  4001545       40 ...ding.WaitCallback  0 instance 000000019f8ccf48 _poolCreateRequest
000007fef7247070  4001546       48 ...Collections.Queue  0 instance 0000000000000000 _deactivateQueue
000007fef7246130  4001547       50 ...ding.WaitCallback  0 instance 0000000000000000 _deactivateCallback
000007fef725ed78  4001548       90         System.Int32  1 instance                0 _waitCount
000007fee0a33928  4001549       58 ...l+PoolWaitHandles  0 instance 000000019f8cc8e8 _waitHandles
000007fef7257dd0  400154a       60     System.Exception  0 instance 0000000000000000 _resError
000007fef7256cd8  400154b       a0       System.Boolean  1 instance                0 _errorOccurred
000007fef725ed78  400154c       94         System.Int32  1 instance             5000 _errorWait
000007fef7289e60  400154d       68 ...m.Threading.Timer  0 instance 0000000000000000 _errorTimer
000007fef7289e60  400154e       70 ...m.Threading.Timer  0 instance 000000019f8cd110 _cleanupTimer
000007fee0a33c58  400154f       78 ...tedConnectionPool  0 instance 000000019f8ccca8 _transactedConnectionPool
0000000000000000  4001550       80                       0 instance 000000019f8cc940 _objectList
000007fef725ed78  4001551       98         System.Int32  1 instance               12 _totalObjects

總結

1. SQL語句 以及 它的類型可以分別從System.Data.SqlClient.SqlCommand對象的_commandText 字段和 _commandType字段中找到.

2. SQLConnection是從ConnectionPool中分配出來.

3. 連接字符串, 以及相應的數據可以從ConnectionPoolOption對象中找到. 它位於SQLConnection對象的_userConnectionOptions字段下.

4. ConnectionPool已經分配的Connection數目, 可以從System.Data.ProviderBase.DbConnectionPool對象的_totalObjects字段中找到. 這個對象位於SQLConnection對象的_innerConnection下面.

 

希望以上內容對您有所幫助

Richard Chen


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM