嘗試辨識正在連接到 SQL Server 中特定數據庫的程序
我正試圖追查……某事……正在與特定數據庫建立連接,而(顯然)沒有對連接做任何事情。但是,到目前為止,我沒有運氣。
該數據庫中的數據已遷移到同一伺服器上的其他數據庫,在開發人員確認他們已更改/刪除對該特定數據庫的所有訪問權限(包括已嵌入但未使用的連接字元串)後,我們將數據庫重命名為類似的東西
DBNAME_Old
。然而,這導致產生分散的錯誤。我們將數據庫重命名為原始名稱,錯誤消失了。然而,在檢查了他們的程式碼之後,開發人員仍然無法辨識任何其他可能導致問題的程式碼。我無法訪問訪問數據庫的程式碼(或者我自己會搜尋它)。
接下來,我設置了一個計劃作業,試圖辨識與數據庫建立的任何連接。我可以通過多種方法辨識數據庫中執行的程序,但在我的監控執行時沒有任何顯示(相對不頻繁,因為沒有猛烈的生產)。
然後我嘗試了幾個擴展事件過程:
-- Attempt 1 - CREATE EVENT SESSION [DBToMonitorMonitoring] ON SERVER ADD EVENT sqlserver.connectivity_ring_buffer_recorded( ACTION(sqlserver.client_app_name,sqlserver.client_connection_id,sqlserver.client_hostname,sqlserver.database_name,sqlserver.nt_username,sqlserver.server_principal_name,sqlserver.session_nt_username,sqlserver.session_server_principal_name,sqlserver.sql_text,sqlserver.username) WHERE ([sqlserver].[equal_i_sql_unicode_string]([sqlserver].[database_name],N'DBToMonitor') AND [sqlserver].[session_server_principal_name]<>N'[THEDOMAIN\Domain_Login]')), ADD EVENT sqlserver.login(SET collect_options_text=(1) ACTION(sqlserver.client_app_name,sqlserver.client_connection_id,sqlserver.client_hostname,sqlserver.database_name,sqlserver.nt_username,sqlserver.server_principal_name,sqlserver.session_nt_username,sqlserver.session_server_principal_name,sqlserver.sql_text,sqlserver.username) WHERE ([database_name]=N'DBToMonitor' OR [sqlserver].[database_name]=N'DBToMonitor')), ADD EVENT sqlserver.logout( ACTION(sqlserver.client_app_name,sqlserver.client_connection_id,sqlserver.client_hostname,sqlserver.database_name,sqlserver.nt_username,sqlserver.server_principal_name,sqlserver.session_nt_username,sqlserver.session_server_principal_name,sqlserver.sql_text,sqlserver.username) WHERE ([sqlserver].[database_name]=N'DBToMonitor')), ADD EVENT sqlserver.rpc_starting(SET collect_statement=(1) ACTION(sqlserver.client_app_name,sqlserver.client_connection_id,sqlserver.client_hostname,sqlserver.database_name,sqlserver.nt_username,sqlserver.server_principal_name,sqlserver.session_nt_username,sqlserver.session_server_principal_name,sqlserver.sql_text,sqlserver.username) WHERE ([sqlserver].[equal_i_sql_unicode_string]([sqlserver].[database_name],N'DBToMonitor') AND [sqlserver].[session_server_principal_name]<>N'[THEDOMAIN\Domain_Login]')), ADD EVENT sqlserver.sql_batch_starting( ACTION(sqlserver.client_app_name,sqlserver.client_connection_id,sqlserver.client_hostname,sqlserver.database_name,sqlserver.nt_username,sqlserver.server_principal_name,sqlserver.session_nt_username,sqlserver.session_server_principal_name,sqlserver.sql_text,sqlserver.username) WHERE ([sqlserver].[equal_i_sql_unicode_string]([sqlserver].[database_name],N'DBToMonitor') AND [sqlserver].[not_equal_i_sql_unicode_string]([sqlserver].[session_server_principal_name],N'AMERICAS\DTNA_S_SQLService'))) ADD TARGET package0.ring_buffer(SET max_events_limit=(400)) WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=ON,STARTUP_STATE=OFF) GO -- Attempt 2 - Found on the internet CREATE EVENT SESSION [DBToMonitor_DB_Usage] ON SERVER ADD EVENT sqlserver.sql_statement_completed( ACTION(sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.username) WHERE ([sqlserver].[database_name]=N'DBToMonitor')) ADD TARGET package0.event_file(SET filename=N'D:\Traces\DBToMonitor_DB_Usage.xel',metadatafile=N'D:\Traces\DBToMonitorDB_Usage.xem') WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF) GO
儘管第二個可以辨識與數據庫的直接連接,但它無法辨識諸如
SELECT TOP 1 * FROM DBToMonitor.dbo.SampleTable
任何有關辨識與特定數據庫中的數據建立的任何連接,或者即使數據庫中沒有數據被觸及的任何登錄的任何建議,都將在這裡得到充分的讚賞,因為我已經在這里達到了我的資源的盡頭,除了猛擊具有持續監控的伺服器會使生產陷入癱瘓。
幫助?
一種方法是將數據庫設置為
AUTO_CLOSE
並擷取database_started
事件,如下例所示。儘管我database_id
在此範例中包含了一個過濾器,但可能不需要它,因為這將(希望)是AUTO_CLOSE
實例上唯一的數據庫。跟踪中的
database_name
將反映使用數據庫的上下文數據庫,例如在跨數據庫查詢中。ALTER DATABASE DeprecatedDatabase SET AUTO_CLOSE ON; GO --get database_id value for the database SELECT DB_ID(N'DeprecatedDatabase') AS DatabaseID; GO --specify above database_id value as session filter CREATE EVENT SESSION DeprecatedDatabaseUsed ON SERVER ADD EVENT sqlserver.database_started( ACTION(sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.database_name,sqlserver.server_principal_name) WHERE ([database_id]=(40))) ADD TARGET package0.event_file(SET filename=N'DeprecatedDatabaseUsed',max_file_size=(100)) WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF) GO ALTER EVENT SESSION DeprecatedDatabaseUsed ON SERVER STATE = START; GO
注意
AUTO_CLOSE
通常是一個壞主意,但我希望在這種情況下不經常使用數據庫,因為它根本不應該使用。我要補充一點,應用程序團隊應該能夠辨識數據庫重命名後程式碼中出現“分散錯誤”的位置。這將查明正在使用數據庫的位置。