sql >> Databáze >  >> RDS >> Sqlserver

Důležitá změna Extended Events v SQL Server 2012

Jak jste jistě slyšeli jinde, SQL Server 2012 konečně nabízí verzi Extended Events, která je životaschopnou alternativou k SQL Trace, pokud jde o lepší výkon a paritu událostí. Existují další vylepšení, jako je použitelné uživatelské rozhraní v Management Studio – dříve byla vaší jedinou nadějí na to Extended Events Manager Jonathana Kehayiase. Je zde také velká změna související s oprávněními:v SQL Server 2012 potřebujete pouze ALTER ANY EVENT SESSION k vytváření a správě relací Extended Event (dříve jste potřebovali CONTROL SERVER ).

Nedávno jsem narazil na jemnější změnu chování, která způsobila, že to vypadalo, že moje relace události vynechává události. Samotná změna není tajemstvím a ve skutečnosti i poté, co jsem o této změně několikrát přečetl nebo o ní slyšel (Jonathan mi připomněl, že mi o této změně také řekl), stále mi při prvním odstraňování problémů chyběla, protože v té době nebyla to změna, o které jsem si myslel, že mě ovlivní. Hle…

Verze TL;DR

V SQL Server 2012 vaše relace události ve výchozím nastavení zachytí pouze 1 000 událostí, pokud používá ring_buffer cíl (a 10 000 za pair_matching ). Jde o změnu oproti 2008 / 2008 R2, kde byla omezena pouze pamětí. (Změna je zde zmíněna téměř v poznámce pod čarou, v červenci 2011.) Chcete-li přepsat výchozí nastavení, můžete použít MAX_EVENTS_LIMIT nastavení – ale mějte na paměti, že toto nastavení nebude SQL Server 2008 / 2008 R2 rozpoznáno, takže pokud máte kód, který musí fungovat s více verzemi, budete muset použít podmíněné.

Další podrobnosti

Scénář, kterým jsem pracoval, byl složitější než tento, ale abychom tento problém demonstrovali, předpokládejme velmi jednoduchý případ použití pro rozšířené události:sledování, kdo upravuje objekty. K tomu existuje šikovná funkce:object_altered . Popis této události můžeme vidět z následujícího dotazu:

SELECT description FROM sys.dm_xe_objects WHERE name = 'object_altered';
Vyvolá se, když byl objekt změněn příkazem ALTER. Tato událost je vyvolána dvakrát pro každou operaci ALTER. Událost je vyvolána, když operace začíná a když je operace buď vrácena zpět, nebo potvrzena. Přidejte k této události akce nt_username nebo server_principal_name, abyste zjistili, kdo objekt změnil.

Takže pokud je objekt upraven, řekněme, 20krát, očekával bych, že vytáhne 40 událostí. A to je přesně to, co se děje v SQL Server 2008, 2008 R2 a 2012. Problém nastává, když dojde k více než 500 úpravám (což vede k více než 1 000 událostem). V SQL Server 2008 a 2008 R2 stále zachycujeme všechny události. Ale SQL Server 2012 některé vypustí kvůli změně v ring_buffer cílová. Pro demonstraci sestavme rychlou ukázkovou relaci události, která vymění výkon za prevenci ztrátových událostí (všimněte si, že toto není sada možností, kterou bych předepsal pro jakýkoli produkční systém):

USE master;
GO
CREATE EVENT SESSION [XE_Alter] ON SERVER
ADD EVENT  sqlserver.object_altered
(
    ACTION (sqlserver.server_principal_name)
    WHERE  (sqlserver.session_id = 78) -- change 78 to your current spid
)
ADD TARGET package0.ring_buffer (SET MAX_MEMORY = 4096)
WITH (EVENT_RETENTION_MODE = NO_EVENT_LOSS, MAX_DISPATCH_LATENCY = 5 SECONDS);
 
ALTER EVENT SESSION [XE_Alter] ON SERVER STATE = START;
GO

Po zahájení relace ve stejném okně spusťte následující skript, který vytvoří dvě procedury a ve smyčce je změní.

CREATE PROCEDURE dbo.foo_x AS SELECT 1;
GO
 
CREATE PROCEDURE dbo.foo_y AS SELECT 1;
GO
 
ALTER PROCEDURE dbo.foo_x AS SELECT 2;
GO 275
 
ALTER PROCEDURE dbo.foo_y AS SELECT 2;
GO 275
 
DROP PROCEDURE dbo.foo_x, dbo.foo_y;
GO

Nyní vytáhneme název objektu a kolikrát byl každý objekt z cíle změněn, a ukončíme relaci události (buďte trpěliví, v mém systému to trvale trvá asi 40 sekund):

;WITH raw_data(t) AS
(
  SELECT CONVERT(XML, target_data)
  FROM sys.dm_xe_sessions AS s
  INNER JOIN sys.dm_xe_session_targets AS st
  ON s.[address] = st.event_session_address
  WHERE s.name = 'XE_Alter'
  AND st.target_name = 'ring_buffer'
),
xml_data (ed) AS
(
  SELECT e.query('.') 
  FROM raw_data 
  CROSS APPLY t.nodes('RingBufferTarget/event') AS x(e)
)
SELECT [object_name] = obj, event_count = COUNT(*)
FROM
(
  SELECT
    --[login] = ed.value('(event/action[@name="server_principal_name"]/value)[1]', 'nvarchar(128)'),
    obj   = ed.value('(event/data[@name="object_name"]/value)[1]', 'nvarchar(128)'),
    phase = ed.value('(event/data[@name="ddl_phase"]/text)[1]',    'nvarchar(128)')
  FROM xml_data
) AS x
WHERE phase = 'Commit'
GROUP BY obj;
GO
 
DROP EVENT SESSION [XE_Alter] ON SERVER;
GO

Výsledky (které ignorují přesně polovinu z 1 000 zachycených událostí se zaměřením na Commit pouze události):

object_name event_count
=======================
foo_x 225
foo_y 275

To ukazuje, že 50 událostí potvrzení (celkem 100 událostí) bylo zrušeno pro foo_x a celkem bylo shromážděno přesně 1 000 událostí ((225 + 275) * 2)). Zdá se, že SQL Server se svévolně rozhoduje, které události vypustí – pokud by teoreticky sbíral 1 000 událostí a pak se zastavil, měl bych mít 275 událostí pro foo_x a 225 pro foo_y , protože jsem změnil foo_x první a neměl jsem narazit na čepici, dokud nebyla ta smyčka dokončena. Ale zjevně zde hrají roli některé další mechanismy v tom, jak XEvents rozhoduje, které události si ponechat a které události zahodit.

V každém případě to můžete obejít zadáním jiné hodnoty pro MAX_EVENTS_LIMIT v ADD TARGET část kódu:

-- ...
ADD TARGET package0.ring_buffer (SET MAX_MEMORY = 4096, MAX_EVENTS_LIMIT = 0)
------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^
-- ...

Všimněte si, že 0 =neomezeno, ale můžete zadat libovolnou celočíselnou hodnotu. Když spustíme výše uvedený test s novým nastavením, uvidíme přesnější výsledky, protože nebyly vynechány žádné události:

object_name event_count
=======================
foo_x 275
foo_y 275

Jak je uvedeno výše, pokud se pokusíte použít tuto vlastnost při vytváření relace události proti SQL Server 2008 / 2008 R2, zobrazí se tato chyba:

Zpráva 25629, Úroveň 16, Stav 1, Řádek 1
Pro cíl „package0.ring_buffer“ neexistuje přizpůsobitelný atribut „MAX_EVENTS_LIMIT“.

Pokud tedy provádíte jakýkoli druh generování kódu a chcete konzistentní chování napříč verzemi, budete muset nejprve zkontrolovat verzi a zahrnout pouze atribut pro rok 2012 a vyšší.

Závěr

Pokud upgradujete z SQL Server 2008 / 2008 R2 na 2012 nebo jste napsali kód Extended Events, který cílí na více verzí, měli byste si být vědomi této změny chování a odpovídajícímu kódu. Jinak riskujete zrušení událostí, a to i v situacích, kdy byste předpokládali – a kde by předchozí chování naznačovalo –, že vyřazené události nejsou možné. To není něco, co vám nástroje jako Upgrade Advisor nebo Best Practices Analyzer ukážou.

Základní mechanismy obklopující tento problém jsou podrobně popsány v této zprávě o chybě a v tomto příspěvku na blogu.


  1. Zřetězení mnoha řádků do jednoho textového řetězce se seskupením

  2. Oprava děr/mezer v číslech generovaných sekvencí Postgres

  3. Před vytvořením dočasné tabulky zkontrolujte, zda existuje dočasná tabulka, a odstraňte, pokud existuje

  4. 4 způsoby, jak získat historii úloh SQL Server