[ Del 1 | Del 2 | Del 3 ]
I del 1 af denne serie forklarede jeg, hvordan jeg nåede frem til den konklusion, at vi skulle deaktivere standardsporingen. I del 2 viste jeg Extended Events-sessionen, som jeg implementerede for at fange alle filstørrelsesændringshændelser. I dette indlæg vil jeg vise de visninger, jeg oprettede for at gøre forbruget af begivenhedsdata lettere for folk, og også for at forklare nogle advarsler.
Fordøjelige visninger
Først oprettede jeg en visning, der ville afsløre de vigtige bits fra Extended Events-sessionsdataene og lægge dem i hjælpedatabasen, der findes på hver instans:
CREATE VIEW dbo.vwFileSizeChanges AS WITH FileInfo(XEPath) AS ( SELECT LEFT(BasePath,COALESCE(NULLIF(CHARINDEX(SessName,BasePath)-1,-1),0)) + SessName + N'*.xel' FROM ( SELECT xmlsrc.data.value(N'(@name)[1]', N'nvarchar(max)'), SessName FROM ( SELECT CONVERT(xml,target_data), s.[name] FROM sys.dm_xe_session_targets AS t INNER JOIN sys.dm_xe_sessions AS s ON s.[address] = t.event_session_address WHERE s.[name] = N'FileSizeChanges' ) AS xefile (TargetData, SessName) CROSS APPLY TargetData.nodes(N'//EventFileTarget/File') AS xmlsrc(data) ) AS InnerData(BasePath, SessName) ), SessionData([EventData]) AS ( SELECT CONVERT(xml, TargetData.event_data) FROM FileInfo CROSS APPLY sys.fn_xe_file_target_read_file(FileInfo.XEPath, NULL, NULL, NULL) AS TargetData ), src AS ( SELECT EndTimeUTC = x.d.value(N'(@timestamp)[1]', N'datetime2'), DatabaseID = x.d.value(N'(data [@name="database_id"]/value)[1]', N'int'), [FileName] = x.d.value(N'(data [@name="file_name"]/value)[1]', N'sysname'), Duration = x.d.value(N'(data [@name="duration"]/value)[1]', N'int'), FileType = x.d.value(N'(data [@name="file_type"]/text)[1]', N'varchar(4)'), Culprit = x.d.value(N'(action[@name="sql_text"]/value)[1]', N'nvarchar(max)'), IsAutomatic = x.d.value(N'(data [@name="is_automatic"]/value)[1]', N'varchar(5)'), ChangeKB = x.d.value(N'(data [@name="size_change_kb"]/value)[1]', N'bigint'), Principal = x.d.value(N'(action[@name="server_principal_name"]/value)[1]', N'sysname'), username = x.d.value(N'(action[@name="username"]/value)[1]', N'sysname'), AppName = x.d.value(N'(action[@name="client_app_name"]/value)[1]', N'sysname'), HostName = x.d.value(N'(action[@name="client_hostname"]/value)[1]', N'sysname') --, [EventData] -- raw XML to troubleshoot specific events FROM SessionData CROSS APPLY EventData.nodes('/event') AS x(d) ) SELECT DatabaseName = DB_NAME(DatabaseID), [FileName], DurationSeconds = CONVERT(decimal(18,3),Duration/1000000.0), StartTimeUTC = CONVERT(datetime2(3), DATEADD(MICROSECOND, -Duration, EndTimeUTC)), EndTimeUTC = CONVERT(datetime2(3), EndTimeUTC), FileType, Culprit = CASE WHEN Culprit IS NULL AND AppName LIKE N'Repl%' THEN AppName ELSE Culprit END, IsAutomatic, ChangeMB = CONVERT(decimal(18,3), ChangeKB / 1024.0), Principal = COALESCE([Principal], COALESCE(NULLIF(username,N''),N'?')), HostName, App = CASE WHEN AppName LIKE N'%Management Studio%Query%' THEN N'SSMS - Query Window' WHEN AppName LIKE N'%Management Studio%' THEN N'SSMS - GUI!' ELSE AppName END--, [EventData] -- raw XML to troubleshoot specific events FROM src;
Når nogen nu vil gennemgå de seneste hændelser for filstørrelsesændringer på en server, kører de:
SELECT <cols> FROM UtilityDatabase.dbo.vwFileSizeChanges ORDER BY StartTimeUTC DESC;
Når du deaktiverer standardsporingen, slettes sporingsfilerne ikke, så alle begivenheder fra før den ændring kan stadig gennemgås. Jeg kan låne fra det faktum, at standardsporingen er hårdkodet til samme sti som SERVERPROPERTY(N'ErrorLogFileName')
, og opret en anden visning, der forbinder ovenstående data med flere data fra standardsporingen:
CREATE VIEW dbo.vwFileSizeChanges_IncludingTrace AS WITH dst AS ( SELECT s,e,d FROM (VALUES ('20190310','20191103',240),('20191103','20200308',300), ('20200308','20201101',240),('20201101','20210314',300), ('20210314','20211107',240)) AS dst(s,e,d) -- arbitrary date range to support DST conversions going a year+ each way -- will add 2022, 2023, etc. later (if DST is still a thing then) ),vars(TracePath) AS ( SELECT REVERSE(SUBSTRING(p, CHARINDEX(N'\', p), 260)) + N'log.trc' FROM (SELECT REVERSE((CONVERT(nvarchar(max), SERVERPROPERTY(N'ErrorLogFileName'))))) AS s(p) ), trc AS ( SELECT t.DatabaseName, t.[FileName], DurationSeconds = CONVERT(decimal(18,3), t.Duration/1000000.0), StartTimeUTC = CONVERT(datetime2(3), DATEADD(MINUTE, COALESCE(st1.d,0), t.StartTime)), EndTimeUTC = CONVERT(datetime2(3), DATEADD(MINUTE, COALESCE(st2.d,0), t.EndTime)), FileType = CASE WHEN t.EventClass IN (92, 94) THEN 'Data' WHEN t.EventClass IN (93, 95) THEN 'Log' END, Culprit = CASE WHEN t.TextData IS NULL AND t. ApplicationName LIKE N'Repl%' THEN t.ApplicationName ELSE t.TextData END, IsAutomatic = 'true', ChangeMB = CONVERT(bigint, t.IntegerData)*8/1024, Principal = t.LoginName, t.HostName, App = CASE WHEN t.ApplicationName LIKE N'%Management Studio%Query%' THEN N'SSMS - Query Window' WHEN t.ApplicationName LIKE N'%Management Studio%' THEN N'SSMS - GUI!' ELSE t.ApplicationName END --, [EventData] = CONVERT(xml, NULL) FROM vars CROSS APPLY sys.fn_trace_gettable(vars.TracePath, DEFAULT) AS t LEFT OUTER JOIN dst AS st1 ON t.StartTime >= DATEADD(HOUR,2,st1.s) AND t.StartTime < DATEADD(HOUR,2,st1.e) LEFT OUTER JOIN dst AS st2 ON t.EndTime >= DATEADD(HOUR,2,st2.s) AND t.EndTime < DATEADD(HOUR,2,st2.e) WHERE t.EventClass IN (92,93) ) SELECT src='trace', * FROM trc UNION ALL SELECT src='xe', * FROM dbo.vwFileSizeChanges;
Denne visning justerer sporingsdataene (fanget i østlig tid på alle vores servere) til UTC og håndterer også sommertid, hvor det er relevant. Hvis dataene falder uden for rækkevidden af CTE kaldet dst
, vil det i stedet blive udtrykt i østlig tid (og du kan nemt rette dette ved at tilføje flere sommertider). Der er en ekstra kolonne kaldet src
så du kan forespørge på de gamle sporingsdata ved hjælp af:
SELECT <cols> FROM UtilityDatabase.dbo.vwFileSizeChanges_IncludingTrace WHERE src = 'trace' ORDER BY StartTimeUTC DESC;
Forbehold
Der er ikke sådan noget som en gratis frokost! Selvom jeg er overbevist om, at fjernelse af standardsporingen vil have nul eller, meget mere sandsynligt, en positiv indvirkning på vores arbejdsbelastning, er der nogle ting, du skal huske på for dit miljø, hvis du vælger at følge min vej:
- Databaser er ikke permanente
I min Extended Events-sessionsdefinition valgte jeg ikke at implementere
collect_database_name
, og i visningen ovenfor kan du se, at jeg løser dette ved kørsel ved hjælp afDB_NAME(database_id)
. Der er en risiko her, ved at nogen kan oprette en database, udføre en masse aktiviteter, der skaber filafgang og disk-thrassing, og derefter droppe databasen.database_id
eksponeret i XML er ikke længere meningsfuldt i dette tilfælde, ogDB_NAME()
vil returnereNULL
.Jeg valgte dette resultat frem for udelukkende at stole på databasenavnet, fordi ovenstående hændelseskæde er langt mindre sandsynlig end et databaseomdøbning (hvor et
database_id
forbliver det samme). I så fald leder du måske efter begivenheder, der skete med en database, men søger med det forkerte (aktuelle) navn, afhængigt af hvornår begivenhederne fandt sted.Hvis du vil være i stand til at bruge den ene eller den anden, kan du bruge følgende sessionsdefinition i stedet:
... ADD EVENT sqlserver.database_file_size_change ( SET collect_database_name = (1) ACTION ( sqlserver.sql_text, ...
Dette kan heller ikke være gratis, ellers ville det ske som standard, men jeg vil indrømme, at jeg aldrig har testet virkningen af at føje det til samlingen.
- SSMS-rapporter vil være lidt mindre pålidelige
En bivirkning ved at deaktivere standardsporingen er at forstyrre nogle af Management Studios "Standard Reports". Jeg spurgte vores teams, før jeg gjorde dette, og du vil gerne gøre det samme for at sikre, at dine brugere ikke stoler på nogen af disse. Du vil også gerne minde dem om, at rapporterne i øjeblikket ikke kan stole på alligevel, af samme grund kan jeg ikke stole på standardsporingen direkte – de kan kun trække data, der stadig er i sporet. En tom rapport betyder ikke nødvendigvis, at der ikke er sket nogen begivenheder; det kan blot betyde, at oplysningerne ikke længere er tilgængelige. Hvis det virkelig er her, et team ønskede at forbruge disse oplysninger, kunne jeg sørge for, at de er pålidelige ved at sende dem tilpassede rapporter, der bruger en mere troværdig kilde.
Følgende rapporter er dem, jeg kunne se, stammer i det mindste nogle af deres oplysninger fra standardsporingen, og hvorfor vi ikke har brug for rapporterne, selvom de kunne stole på:
Skemaændringshistorik Vi har allerede kildekontrol, en streng gennemgang/implementeringsproces og DDL-triggere på plads, der fanger oplysninger om skemaændringer. Konfigurationsændringshistorik
og
HukommelsesforbrugVores overvågningsværktøj fortæller os om konfigurationsændringer på instansniveau, så denne rapport i SSMS er overflødig. Loginfejl Disse er i fejlloggen (og begivenhedsfremviseren), fordi vi som standard aktiverer "Failed logins only" revision for alle SQL Server-instanser. Nogle servere har også yderligere formel revision af overholdelseshensyn. Diskbrug Blandt anden information viser dette hændelser for autovækst og automatisk krympning fra standardsporingen, som vi nu fanger ved hjælp af udvidede hændelser. Backup og gendannelse af begivenheder Denne information er let tilgængelig i msdb.dbo.backupset, hvis vi nogensinde får brug for dem, men disse er også rullet ind i vores automatisering omkring sikkerhedskopiering og gendannelse (vi ser aldrig på standardsporingen for denne information).
Databasekonsistenshistorik Som med sikkerhedskopier har vi automatisering bygget op omkring DBCC CHECKDB; hvis nogen gik uden for dette og kørte noget manuelt, vil det stadig dukke op i fejlloggen. Og vi har meget mere kontrol over, hvor længe vi opbevarer fejllogs, og hvor ofte vi genbruger dem. Vi genbruger hver nat, så det er nemmere at finde en begivenhed, som vi har mistanke om, er sket på en given dag i fortiden.
Konklusion
Dette var et sjovt, men kompliceret projekt, og jeg er tilfreds med resultatet indtil videre. Tak fordi du tog med!
[ Del 1 | Del 2 | Del 3 ]