[ Část 1 | Část 2 | Část 3 ]
V části 1 této série jsem vysvětlil, jak jsem dospěl k závěru, že bychom měli zakázat výchozí trasování. V části 2 jsem ukázal relaci Extended Events, kterou jsem nasadil k zachycení všech událostí změny velikosti souboru. V tomto příspěvku chci ukázat pohledy, které jsem vytvořil, abych lidem usnadnil spotřebu dat událostí a také vysvětlil některá upozornění.
Stravitelná zobrazení
Nejprve jsem vytvořil pohled, který by odhalil důležité části z dat relace Extended Events, a vložil jej do databáze nástrojů, která existuje u každé instance:
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;
Nyní, když chce někdo zkontrolovat nedávné události změny velikosti souboru na libovolném serveru, spustí:
SELECT <cols> FROM UtilityDatabase.dbo.vwFileSizeChanges ORDER BY StartTimeUTC DESC;
Když zakážete výchozí trasování, trasovací soubory nebudou odstraněny, takže všechny události z doby před touto změnou jsou stále kontrolovatelné. Mohu si vypůjčit ze skutečnosti, že výchozí trasování je pevně zakódováno do stejné cesty jako SERVERPROPERTY(N'ErrorLogFileName')
a vytvořte druhý pohled, který spojí výše uvedená data s dalšími daty z výchozího trasování:
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;
Toto zobrazení upravuje trasovací data (zachycená ve východním čase na všech našich serverech) na UTC a zpracovává DST tam, kde je to vhodné. Pokud data spadají mimo rozsah CTE nazývaného dst
, bude místo toho vyjádřeno ve východním čase (a můžete to snadno opravit přidáním dalších rozsahů DST). Existuje další sloupec nazvaný src
takže můžete dotazovat stará data trasování pomocí:
SELECT <cols> FROM UtilityDatabase.dbo.vwFileSizeChanges_IncludingTrace WHERE src = 'trace' ORDER BY StartTimeUTC DESC;
Upozornění
Nic takového jako oběd zdarma neexistuje! I když jsem přesvědčen, že odstranění výchozího trasování bude mít nulový nebo mnohem pravděpodobnější pozitivní dopad na naše pracovní vytížení, existuje několik věcí, které je třeba mít na paměti pro vaše prostředí, pokud se rozhodnete následovat moji cestu:
- Databáze nejsou trvalé
V definici relace Extended Events jsem se rozhodl neimplementovat
collect_database_name
a ve výše uvedeném pohledu můžete vidět, že to řeším za běhu pomocíDB_NAME(database_id)
. Existuje zde riziko, že by někdo mohl vytvořit databázi, provést spoustu činností, při kterých dochází k vracení souborů a drcení disku, a pak databázi zahodit.database_id
vystavený v XML již v tomto případě nemá smysl aDB_NAME()
vrátíNULL
.Zvolil jsem tento výsledek před spoléháním se pouze na název databáze, protože výše uvedený řetězec událostí je mnohem méně pravděpodobný než přejmenování databáze (kde
database_id
zůstane stejný). V takovém případě možná hledáte události, které se staly v databázi, ale hledáte pomocí nesprávného (aktuálního) názvu v závislosti na tom, kdy se události staly.Pokud chcete mít možnost používat jedno nebo druhé, můžete místo toho použít následující definici relace:
... ADD EVENT sqlserver.database_file_size_change ( SET collect_database_name = (1) ACTION ( sqlserver.sql_text, ...
Ani to nemůže být zdarma, nebo by se to stalo ve výchozím nastavení, ale přiznám se, že jsem nikdy netestoval dopad přidání tohoto do sbírky.
- Přehledy SSMS budou o něco méně spolehlivé
Vedlejším efektem deaktivace výchozího trasování je narušení některých standardních sestav Management Studio. Než jsem to udělal, dotazoval jsem se našich týmů a vy budete chtít udělat totéž, abyste se ujistili, že vaši uživatelé na nic z toho nespoléhají. Také jim budete chtít připomenout, že na sestavy se v současné době stejně nelze spolehnout, ze stejného důvodu, proč se nemohu přímo spolehnout na výchozí trasování – mohou stahovat pouze data, která jsou stále ve trasování. Prázdná zpráva nutně neznamená, že se žádné události nestaly; může to znamenat, že informace již nejsou k dispozici. Pokud je to skutečně místo, kde chtěl tým tyto informace využít, mohl bych se ujistit, že jsou spolehlivé, tím, že jim dodám vlastní přehledy, které používají důvěryhodnější zdroj.
Následující přehledy jsou ty, u kterých jsem viděl, že odvozují alespoň některé informace z výchozího trasování a proč tyto přehledy nepotřebujeme, i když jim lze důvěřovat:
Historie změn schématu Už máme kontrolu zdroje, přísný proces kontroly / nasazení a spouštěče DDL, které zachycují informace o změnách schématu. Historie změn konfigurace
a
Spotřeba pamětiNáš monitorovací nástroj nás informuje o změnách konfigurace na úrovni instance, takže tato zpráva v SSMS je nadbytečná. Chyby přihlášení Jsou v protokolu chyb (a v prohlížeči událostí), protože standardně povolujeme auditování „Pouze neúspěšná přihlášení“ pro všechny instance SQL Serveru. Některé servery mají také další formální audit z důvodu souladu. Využití disku Mimo jiné zde jsou uvedeny události autogrowth a autoshrink z výchozího trasování, které nyní zachycujeme pomocí Extended Events. Události zálohování a obnovení Tyto informace jsou snadno dostupné v msdb.dbo.backupset, pokud je budeme někdy potřebovat, ale jsou také součástí naší automatizace zálohování a obnovy (nikdy se nedíváme na výchozí trasování těchto informací).
Historie konzistence databáze Stejně jako u záloh máme automatizaci postavenou na DBCC CHECKDB; pokud někdo šel mimo toto a spustil něco ručně, stále se to zobrazí v protokolu chyb. A máme mnohem větší kontrolu nad tím, jak dlouho uchováváme protokoly chyb a jak často je recyklujeme. Každou noc recyklujeme, abychom snáze našli událost, o které máme podezření, že se stala v daný den v minulosti.
Závěr
Byl to zábavný, ale komplikovaný projekt a s výsledkem jsem zatím spokojen. Díky, že jste s námi jeli!
[ Část 1 | Část 2 | Část 3 ]