Üzerinde toplarken sqlserver.read_only_route_completeKin ve Remus tarafından belirtilen Genişletilmiş Olay, bir güzel ayıklama olay, ama onunla bilgilerin büyük bir taşınmaz - sadece route_port(örneğin 1433) ve route_server_name(örneğin sqlserver-0.contoso.com) varsayılan olarak . Bu aynı zamanda salt okunur bir niyet bağlantısının ne zaman başarılı olduğunu belirlemeye yardımcı olacaktır. Bir read_only_route_failolay var, ancak ateşlenemedim, belki yönlendirme URL’si ile ilgili bir sorun varsa, ikincil örnek kullanamadığım / kullanamadığım kadarıyla patlayabiliyordu.
Bununla birlikte, sqlserver.loginolayı etkinleştirmek ve nedensellik izlemenin etkin olması ve buna yardımcı olacak bazı eylemlerin (benzeri sqlserver.username) katılmasıyla bir miktar başarı elde ettim.
Reprodüksiyon Adımları
Alakalı olayları, ayrıca yararlı eylemleri ve nedenselliği izlemek için bir Genişletilmiş Olaylar oturumu oluşturun:
CREATE EVENT SESSION [xe_watchLoginIntent] ON SERVER
ADD EVENT sqlserver.login
( ACTION ( sqlserver.username ) ),
ADD EVENT sqlserver.read_only_route_complete
( ACTION (
sqlserver.client_app_name,
sqlserver.client_connection_id,
sqlserver.client_hostname,
sqlserver.client_pid,
sqlserver.context_info,
sqlserver.database_id,
sqlserver.database_name,
sqlserver.username
) ),
ADD EVENT sqlserver.read_only_route_fail
( ACTION (
sqlserver.client_app_name,
sqlserver.client_connection_id,
sqlserver.client_hostname,
sqlserver.client_pid,
sqlserver.context_info,
sqlserver.database_id,
sqlserver.database_name,
sqlserver.username
) )
ADD TARGET package0.event_file( SET filename = N'xe_watchLoginIntent' )
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, --<-- relate events
STARTUP_STATE = ON --<-- ensure sessions starts after failover
)
XE oturumunu çalıştırın (bu bir Debug olayı gibi örneklemeyi düşünün) ve bazı girişler toplayın:

Buradaki not sqlserver-0 okunabilir ikincil ve sqlserver-1 birincildir. Burada salt okunur uygulama amaçlı girişleri ve bazı SQL girişlerini simüle etmek için -Kanahtarını kullanıyorum sqlcmd. Salt okunur olay, salt okunur amaçlı başarılı bir oturum açma işlemine başlar.
Oturumu duraklatmak veya durdurmak üzerine sorgulayabilirim ve iki olayı birleştirmeyi deneyebilirim, örneğin:
DROP TABLE IF EXISTS #tmp
SELECT IDENTITY( INT, 1, 1 ) rowId, file_offset, CAST( event_data AS XML ) AS event_data
INTO #tmp
FROM sys.fn_xe_file_target_read_file( 'xe_watchLoginIntent*.xel', NULL, NULL, NULL )
ALTER TABLE #tmp ADD PRIMARY KEY ( rowId );
CREATE PRIMARY XML INDEX _pxmlidx_tmp ON #tmp ( event_data );
-- Pair up the login and read_only_route_complete events via xxx
DROP TABLE IF EXISTS #users
SELECT
rowId,
event_data.value('(event/@timestamp)[1]', 'DATETIME2' ) AS [timestamp],
event_data.value('(event/action[@name="username"]/value/text())[1]', 'VARCHAR(100)' ) AS username,
event_data.value('(event/action[@name="attach_activity_id_xfer"]/value/text())[1]', 'VARCHAR(100)' ) AS attach_activity_id_xfer,
event_data.value('(event/action[@name="attach_activity_id"]/value/text())[1]', 'VARCHAR(100)' ) AS attach_activity_id
INTO #users
FROM #tmp l
WHERE l.event_data.exist('event[@name="login"]') = 1
AND l.event_data.exist('(event/action[@name="username"]/value/text())[. = "SqlUserShouldBeReadOnly"]') = 1
DROP TABLE IF EXISTS #readonly
SELECT *,
event_data.value('(event/@timestamp)[1]', 'DATETIME2' ) AS [timestamp],
event_data.value('(event/data[@name="route_port"]/value/text())[1]', 'INT' ) AS route_port,
event_data.value('(event/data[@name="route_server_name"]/value/text())[1]', 'VARCHAR(100)' ) AS route_server_name,
event_data.value('(event/action[@name="username"]/value/text())[1]', 'VARCHAR(100)' ) AS username,
event_data.value('(event/action[@name="client_app_name"]/value/text())[1]', 'VARCHAR(100)' ) AS client_app_name,
event_data.value('(event/action[@name="attach_activity_id_xfer"]/value/text())[1]', 'VARCHAR(100)' ) AS attach_activity_id_xfer,
event_data.value('(event/action[@name="attach_activity_id"]/value/text())[1]', 'VARCHAR(100)' ) AS attach_activity_id
INTO #readonly
FROM #tmp
WHERE event_data.exist('event[@name="read_only_route_complete"]') = 1
SELECT *
FROM #users u
LEFT JOIN #readonly r ON u.attach_activity_id_xfer = r.attach_activity_id_xfer
SELECT u.username, COUNT(*) AS logins, COUNT( DISTINCT r.rowId ) AS records
FROM #users u
LEFT JOIN #readonly r ON u.attach_activity_id_xfer = r.attach_activity_id_xfer
GROUP BY u.username
Sorgu, uygulama salt okunur amacı olan ve olmayan girişleri göstermelidir:

read_only_route_completeBu bir Debug olayıdır, bu nedenle dikkatli kullanın. Örneğin örneklemeyi düşünün.
- İki yolun nedenselliğiyle birlikte bu olay, ihtiyacınızı yerine getirme potansiyeli sunuyor - bu basit teçhizat için daha ileri testler gerekli
- Bağlantıda veritabanı adı belirtilmemişse, işler işe yaramadıysa fark ettim.
pair_matchingÇalışmayı hedeflemeye çalıştım ama zamanım tükendi. Burada gelişme için bazı potansiyeller var:
ALTER EVENT SESSION [xe_watchLoginIntent] ON SERVER
ADD TARGET package0.pair_matching (
SET begin_event = N'sqlserver.login',
begin_matching_actions = N'sqlserver.username',
end_event = N'sqlserver.read_only_route_complete',
end_matching_actions = N'sqlserver.username'
)