Min kollega, Erin Stellato, ställde nyligen en fråga till mig om var och varför händelseförlust kunde inträffa med Extended Events. Frågan var resultatet av en kommentar som någon hade gjort på ett av hennes blogginlägg som hävdade att showplan_xml
händelser kan inte samlas in av XE Profiler eller genom en "live" ström av händelserna från servern. Jag råkar veta att detta inte är korrekt eftersom jag rutinmässigt har visat de negativa prestandaeffekterna av att använda post_query_execution_showplan-händelsen mot en produktionsbelastning genom att lägga till händelsen i användargränssnittet och låta den titta på livedata, så detta startade en mer djupgående diskussion om hur och när Extended Events kommer att kassera en händelse som har genererats under datainsamlingen.
Händelsens storlek spelar roll
Extended Events konfigurerar internminnesbuffertutrymme för en händelsesession när den initialt startas på servern, och konfigurationen av händelsesessionsalternativen avgör hur stora minnesbuffertar är och den maximala storleken på händelsen som händelsesessionen kan samla in. Medan de flesta händelser som genereras av Extended Events är relativt lätta och små i binärt format, kan specifika händelser generera en mycket större nyttolast av data som måste buffras. Standardalternativen för händelsesessioner resulterar i en sessionskonfiguration med tre interna minnesbuffertar för att hålla händelser som är 1 441 587 byte stora. Storleken och antalet minnesbuffertar för en händelsesession kan hittas i sys.dm_xe_sessions DMV medan sessionen STATE=START på servern:
SELECT s.name, s.total_regular_buffers, s.regular_buffer_size, s.total_large_buffers, s.large_buffer_size, s.total_buffer_sizeFROM sys.dm_xe_sessions AS s;
Observera att det finns noll stora buffertar för var och en av de systemdefinierade händelsesessionerna, och den stora buffertstorleken är också inställd på noll, vilket är standardkonfigurationen. De stora buffertarna för en händelsesession skapas endast när sessionsalternativet MAX_EVENT_SIZE är konfigurerat för händelsesessionen. Standardvärdet för detta alternativ är 0, vilket betyder att den största händelsen som händelsesessionen faktiskt kan konsumera är storleken på en vanlig minnesbuffert, som är 1 441 587 byte. För vissa händelser, som de som producerar showplan_xml, är det faktiskt relativt enkelt att ha en händelsestorlek som är större än standardminnets buffertstorlek för händelsesessionen. I dessa fall skulle den stora händelsen faktiskt kasseras av händelsesessionen eftersom den inte kan placeras i en minnesbuffert för sändning.
Kontrollera händelseförlust
Det finns tre specifika sessionsalternativ som avgör hur stor av en händelse en händelsesession faktiskt kan samla in, och en som styr hur händelser släpps när buffertminnet för händelsesessionen är fullt eller under tryck. Alla dessa fyra har betydelse när vi pratar om att samla in evenemang som skulle kunna generera en stor evenemangsnyttolast och vi vill minimera chansen att vi potentiellt kan släppa ett evenemang. Ett exempel på händelsesession som skulle vara benägen att förlora händelse på grund av minnestryck i buffertutrymmet för händelsesessionen är nedan:
SKAPA HÄNDELSESESSION [Lås] PÅ SERVER LÄGG TILL HÄNDELSE sqlserver.lock_acquired,LÄGG TILL HÄNDELSE sqlserver.lock_releasedADD TARGET package0.event_file(SET filename=N'Locks',max_file_size=(5),max_rollover_MERY=(MAX_4)_MERY==4096 KB,MEMORY_PARTITION_MODE=INGEN,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_EVENT_SIZE=0 KB);
Obs:Det här är inte en händelsesession som jag någonsin skulle rekommendera att köra på en produktionsbelastning – mängden data som den skulle generera skulle vara betydande, eftersom den spårar varje lås som hämtas och släpps.
Om vi startar den här sessionen och sedan kör AdventureWorks Books Online Workload-generator som är tillgänglig på min blogg mot en instans av SQL Server, kommer sessionen snabbt att börja tappa händelser på grund av den snabba händelsegenereringen och fördröjningen i buffertspolning till målet event_file som är konfigurerad. Antalet händelser som har avbrutits av en händelsesession kan spåras i sys.dm_xe_sessions DMV om alternativen för händelsesessionen har konfigurerats med EVENT_RETENTION_MODE =ALLOW_SINGLE_EVENT_LOSS. Om händelsesessionen är konfigurerad med EVENT_RETENTION_MODE=ALLOW_MULTIPLE_EVENT_LOSS kan hela minnesbuffertar av händelser tas bort och den räknar bara hur många buffertar som tappades och inte antalet enskilda händelser som varje buffert innehöll.
SELECT s.name, s.total_regular_buffers, s.regular_buffer_size, s.total_large_buffers, s.large_buffer_size, s.dropped_event_count, s.dropped_buffer_count, s.largest_event_event_dropped_size_sm>AS
Här kan vi se att 100 521 händelser släpptes och den största storleken på en händelse som släpptes var 176 byte, vilket är mindre än storleken på vårt vanliga buffertutrymme, så vi träffar bara normalt buffertminnesutrymmestryck. Men om vi skapar en evenemangssession som samlar de två av showplan-händelserna (se den här artikeln för varför detta kommer att negativt påverka prestandan allvarligt och inte bör göras på produktionsservrar), tillsammans med batchstartande och slutförda händelser och genererar några större planer kan vi utlösa händelseförlust på grund av händelsestorlek.
SKAPA EVENT SESSION [DropsEvents] PÅ SERVER ADD EVENT sqlserver.query_post_execution_showplan,ADD EVENT sqlserver.query_pre_execution_showplan,ADD EVENT sqlserver.sql_batch_completed,ADD_slserver EVENT;
Här kan vi se att large_event_dropped_size är större än vår regular_buffer_size, så det betyder att vi måste ändra konfigurationen av våra sessionsbuffertar. Om vi ökar MAX_MEMORY för händelsesessionen kan det öka storleken på våra vanliga buffertar. Standardvärdet är bara 4MB, vilket är där buffertstorleken på 1,4MB som visas ovan kommer ifrån. Om vi ändrar detta till 64 MB för evenemangssessionen, kommer regular_buffer_size att vara 22,4 MB i storlek vilket skulle rymma vår 3,7 MB tappade händelse. Det andra alternativet är att ställa in alternativet MAX_EVENT_SIZE som ger large_buffer_size för stora evenemang och delas med två för sessionen.
Skapa händelsessession [CollectesEvents] på server lägg till händelse sqlserver.query_post_execution_showplan, lägg till händelse sqlserver.query_pre_execution_showplan
Så här kan vi se de två stora buffertarna med en storlek på 33,6 MB och efter att ha kört samma plan som genererar arbetsbelastning igen har vi inga tappade händelser för vår nya CollectsEvents-session, men vi har fördubblat de tappade händelserna för vår DropsEvents-session med standardinställningarna.
Så, där har du det; varför vissa händelser kanske inte samlas in av en händelsesession, hur man går till väga för att felsöka när händelser släpps och hur man avgör om det är storleken på händelsen som orsakar problemet. Många av de sessioner som jag ser i faktisk användning på klientsystem har standardinställningarna för alternativ för händelsesessioner, särskilt när det kommer till minne. Det här är ett område där du, när du väl förstår buffringsmekanismen som används av utökade händelser och sedan överväger storleken på de händelser som potentiellt kan genereras, kommer att börja göra ändringar i hur sessionsalternativen definieras för att minimera potentialen för händelser tas bort på grund av minnesutrymmesbegränsningar eller begränsningar av händelsestorlek.