Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Важна промяна в разширените събития в SQL Server 2012

Както със сигурност сте чували другаде, SQL Server 2012 най-накрая предлага версия на разширени събития, която е жизнеспособна алтернатива на SQL Trace по отношение както на по-добра производителност, така и на паритет на събитията. Има и други подобрения, като използваем потребителски интерфейс в Management Studio – преди единствената ви надежда за това беше мениджърът на разширени събития на Джонатан Кехайас. Има и голяма промяна, свързана с разрешенията:в SQL Server 2012 имате нужда само от ALTER ANY EVENT SESSION за създаване и управление на разширени сесии на събития (преди това ви трябваше CONTROL SERVER ).

Наскоро се натъкнах на по-фина промяна в поведението, която направи да изглежда, че сесията на събитието ми изпуска събития. Самата промяна не е тайна и всъщност дори след като прочетох или чух за тази промяна няколко пъти (Джонатан ми напомни, че и той ми каза за тази промяна), все още я пропуснах при първоначалното си отстраняване на неизправности, тъй като по това време тя не беше промяна, която смятах, че ще ме засегне. Ето…

TL;DR версия

В SQL Server 2012 вашата сесия за събития ще улови само 1000 събития по подразбиране, ако използва ring_buffer цел (и 10 000 за pair_matching ). Това е промяна от 2008 / 2008 R2, където беше ограничена само от паметта. (Промяната е спомената почти в бележка под линия тук, още през юли 2011 г.) За да отмените настройката по подразбиране, можете да използвате MAX_EVENTS_LIMIT настройка – но имайте предвид, че тази настройка няма да бъде разпозната от SQL Server 2008 / 2008 R2, така че ако имате код, който трябва да работи срещу множество версии, ще трябва да използвате условно условие.

Още подробности

Сценарият, през който работих, беше по-сложен от този, но за да демонстрираме този проблем, нека приемем много прост случай на използване на разширени събития:проследяване кой променя обекти. Има удобно средство за това:object_altered . Можем да видим описанието на това събитие от следната заявка:

SELECT description FROM sys.dm_xe_objects WHERE name = 'object_altered';
Възниква, когато обект е променен от оператора ALTER. Това събитие се издига два пъти за всяка операция ALTER. Събитието се издига, когато операцията започне и когато операцията е или връщана назад, или ангажимент. Добавете действията nt_username или server_principal_name към това събитие, за да определите кой е променил обекта.

Така че, ако обект е модифициран, да речем, 20 пъти, бих очаквал да изтеглим 40 събития. И точно това се случва в SQL Server 2008, 2008 R2 и 2012. Предизвикателството идва, когато се случат повече от 500 модификации (водещи до повече от 1000 събития). В SQL Server 2008 и 2008 R2 ние все още улавяме всички събития. Но SQL Server 2012 ще изпусне някои поради промяна в ring_buffer цел. За да демонстрираме, нека изградим бърза примерна сесия за събитие, която търгува с производителност за предотвратяване на загуба на събития (обърнете внимание, че това не е наборът от опции, които бих предписал за всяка производствена система):

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

Когато сесията стартира, в същия прозорец изпълнете следния скрипт, който създава две процедури и ги променя в цикъл.

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

Сега, нека изтеглим името на обекта и колко пъти всеки обект е бил модифициран от целта и да пуснем сесията на събитието (бъдете търпеливи; в моята система това постоянно отнема около 40 секунди):

;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

Резултати (които игнорират точно половината от 1000 заснети събития, фокусирани върху Commit само събития):

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

Това показва, че 50 commit събития (общо 100 събития) са отпаднали за foo_x , и са събрани точно 1000 общо събития ((225 + 275) * 2)). SQL Server изглежда произволно решава кои събития да отпадне – на теория, ако събираше 1000 събития и след това спираше, трябваше да имам 275 събития за foo_x и 225 за foo_y , тъй като промених foo_x първо и не трябваше да удрям капачката, докато не завърши този цикъл. Но очевидно има някои други механизми, които играят тук как XEvents решава кои събития да запазят и кои да изхвърли.

Във всеки случай можете да заобиколите това, като посочите различна стойност за MAX_EVENTS_LIMIT в ADD TARGET част от кода:

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

Имайте предвид, че 0 =неограничено, но можете да посочите всяка стойност на цяло число. Когато изпълним нашия тест по-горе с новата настройка, виждаме по-точни резултати, тъй като няма изпуснати събития:

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

Както бе споменато по-горе, ако се опитате да използвате това свойство, когато създавате сесия на събитие срещу SQL Server 2008 / 2008 R2, ще получите тази грешка:

Съобщение 25629, ниво 16, състояние 1, ред 1
За цел, "package0.ring_buffer", адаптивният атрибут, "MAX_EVENTS_LIMIT", не съществува.

Така че, ако правите някакъв вид генериране на код и искате последователно поведение между версиите, първо ще трябва да проверите версията и да включите само атрибута за 2012 г. и по-нови.

Заключение

Ако надстройвате от SQL Server 2008 / 2008 R2 до 2012 или сте написали код за разширени събития, който е насочен към множество версии, трябва да сте наясно с тази промяна в поведението и съответно кода. В противен случай рискувате да отпаднете събития, дори в ситуации, в които бихте предположили – и където предишното поведение би предполагало – че отпадналите събития не са възможни. Това не е нещо, което инструменти като съветника за надстройка или анализатора на най-добрите практики ще ви посочат.

Основните механизми около този проблем са описани подробно в този доклад за грешки и тази публикация в блога.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Добавете обобщен ред с общи суми

  2. Настройка и конфигуриране на винаги включена група за наличност в SQL Server

  3. 5 Навици за наблюдение на база данни на успешните администратори на база данни

  4. Резултати от заявка по имейл като HTML таблица в SQL Server (T-SQL)

  5. Търсенето на пълен текст не работи, ако е включена спираща дума, въпреки че списъкът със стоп думи е празен