Sql-Server

嘗試辨識正在連接到 SQL Server 中特定數據庫的程序

  • September 6, 2019

我正試圖追查……某事……正在與特定數據庫建立連接,而(顯然)沒有對連接做任何事情。但是,到目前為止,我沒有運氣。

該數據庫中的數據已遷移到同一伺服器上的其他數據庫,在開發人員確認他們已更改/刪除對該特定數據庫的所有訪問權限(包括已嵌入但未使用的連接字元串)後,我們將數據庫重命名為類似的東西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通常是一個壞主意,但我希望在這種情況下不經常使用數據庫,因為它根本不應該使用。

我要補充一點,應用程序團隊應該能夠辨識數據庫重命名後程式碼中出現“分散錯誤”的位置。這將查明正在使用數據庫的位置。

引用自:https://dba.stackexchange.com/questions/247105