Seperti yang pasti sudah Anda dengar di tempat lain, SQL Server 2012 akhirnya menawarkan versi Extended Events yang merupakan alternatif yang layak untuk SQL Trace, dalam hal kinerja dan paritas acara yang lebih baik. Ada peningkatan lain seperti UI yang dapat digunakan di Management Studio – sebelumnya satu-satunya harapan Anda untuk ini adalah Extended Events Manager dari Jonathan Kehayias. Ada juga perubahan besar terkait izin:di SQL Server 2012 Anda hanya perlu ALTER ANY EVENT SESSION
untuk membuat dan mengelola sesi Acara yang Diperpanjang (sebelumnya Anda memerlukan CONTROL SERVER
).
Saya menemukan perubahan perilaku yang lebih halus baru-baru ini yang membuatnya tampak seperti sesi acara saya menjatuhkan acara. Perubahan itu sendiri bukanlah rahasia, dan bahkan setelah membaca atau mendengar tentang perubahan ini beberapa kali (Jonathan mengingatkan saya bahwa dia memberi tahu saya tentang perubahan ini juga), saya masih melewatkannya dalam pemecahan masalah awal saya karena, pada saat itu, itu bukan perubahan yang saya pikir akan mempengaruhi saya. Lihatlah…
Versi TL;DR
Di SQL Server 2012, sesi acara Anda hanya akan menangkap 1.000 acara secara default jika menggunakan ring_buffer
target (dan 10.000 untuk pair_matching
). Ini adalah perubahan dari 2008/2008 R2, di mana hanya dibatasi oleh memori. (Perubahan disebutkan hampir di catatan kaki di sini, pada Juli 2011.) Untuk mengganti default, Anda dapat menggunakan MAX_EVENTS_LIMIT
pengaturan – tetapi perhatikan bahwa pengaturan ini tidak akan dikenali oleh SQL Server 2008 / 2008 R2, jadi jika Anda memiliki kode yang perlu bekerja dengan beberapa versi, Anda harus menggunakan kondisi.
Rincian Lebih Lanjut
Skenario yang saya kerjakan lebih kompleks dari ini, tetapi untuk mendemonstrasikan masalah ini, mari kita asumsikan kasus penggunaan yang sangat sederhana untuk Peristiwa yang Diperpanjang:melacak siapa yang memodifikasi objek. Ada fasilitas praktis untuk ini:object_altered
. Deskripsi acara ini dapat kita lihat dari query berikut:
SELECT description FROM sys.dm_xe_objects WHERE name = 'object_altered';Terjadi ketika sebuah objek diubah oleh pernyataan ALTER. Event ini dimunculkan dua kali untuk setiap operasi ALTER. Acara dibangkitkan ketika operasi dimulai dan ketika operasi dibatalkan atau dilakukan. Tambahkan tindakan nt_username atau server_principal_name ke acara ini untuk menentukan siapa yang mengubah objek.
Jadi, jika suatu objek dimodifikasi, katakanlah, 20 kali, saya berharap untuk menarik 40 peristiwa. Dan inilah yang terjadi di SQL Server 2008, 2008 R2 dan 2012. Tantangannya datang ketika lebih dari 500 modifikasi terjadi (menghasilkan lebih dari 1.000 peristiwa). Di SQL Server 2008 dan 2008 R2, kami masih merekam semua peristiwa. Tapi SQL Server 2012 akan turun beberapa karena perubahan ring_buffer
target. Untuk mendemonstrasikannya, mari kita buat sesi acara sampel cepat yang memperdagangkan kinerja untuk pencegahan kerugian peristiwa (perhatikan bahwa ini bukan serangkaian opsi yang akan saya berikan untuk sistem produksi apa pun):
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
Dengan sesi dimulai, di jendela yang sama, jalankan skrip berikut, yang membuat dua prosedur, dan mengubahnya dalam satu lingkaran.
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
Sekarang, mari kita tarik nama objek, dan berapa kali setiap objek dimodifikasi dari target, dan lepaskan sesi acara (bersabarlah; di sistem saya, ini secara konsisten membutuhkan waktu sekitar 40 detik):
;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
Hasil (yang mengabaikan tepat setengah dari 1.000 peristiwa yang direkam, dengan fokus pada Commit
acara saja):
=======================
foo_x 225
foo_y 275
Ini menunjukkan bahwa 50 peristiwa komit (total 100 peristiwa) dibatalkan untuk foo_x
, dan tepat 1.000 total peristiwa telah dikumpulkan ((225 + 275) * 2)). SQL Server tampaknya secara sewenang-wenang memutuskan acara mana yang akan dijatuhkan - secara teori, jika mengumpulkan 1.000 acara dan kemudian berhenti, saya harus memiliki 275 acara untuk foo_x
, dan 225 untuk foo_y
, karena saya mengubah foo_x
pertama, dan saya seharusnya tidak menekan tutupnya sampai setelah loop itu selesai. Tapi jelas ada beberapa mekanisme lain yang berperan di sini dalam cara XEvents memutuskan acara mana yang akan disimpan dan acara mana yang harus dibuang.
Bagaimanapun, Anda dapat menyiasatinya dengan menentukan nilai yang berbeda untuk MAX_EVENTS_LIMIT
di ADD TARGET
bagian dari kode:
-- ... ADD TARGET package0.ring_buffer (SET MAX_MEMORY = 4096, MAX_EVENTS_LIMIT = 0) ------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^ -- ...
Perhatikan bahwa 0 =tidak terbatas, tetapi Anda dapat menentukan nilai bilangan bulat apa pun. Saat kami menjalankan pengujian kami di atas dengan setelan baru, kami melihat hasil yang lebih akurat, karena tidak ada peristiwa yang dibatalkan:
object_name event_count=======================
foo_x 275
foo_y 275
Seperti disebutkan di atas, jika Anda mencoba menggunakan properti ini saat membuat sesi acara terhadap SQL Server 2008/2008 R2, Anda akan mendapatkan kesalahan ini:
Msg 25629, Level 16, Status 1, Baris 1Untuk target, "package0.ring_buffer", atribut yang dapat disesuaikan, "MAX_EVENTS_LIMIT", tidak ada.
Jadi, jika Anda melakukan pembuatan kode apa pun dan menginginkan perilaku yang konsisten di seluruh versi, Anda harus memeriksa versinya terlebih dahulu, dan hanya menyertakan atribut untuk tahun 2012 ke atas.
Kesimpulan
Jika Anda memutakhirkan dari SQL Server 2008/2008 R2 ke 2012, atau telah menulis kode Peristiwa yang Diperpanjang yang menargetkan beberapa versi, Anda harus menyadari perubahan perilaku ini dan kode yang sesuai. Jika tidak, Anda berisiko membatalkan acara, bahkan dalam situasi di mana Anda akan berasumsi – dan di mana perilaku sebelumnya menyiratkan – bahwa acara yang dibatalkan itu tidak mungkin. Ini bukan sesuatu yang akan ditunjukkan oleh Alat Penasihat Peningkatan atau Penganalisis Praktik Terbaik untuk Anda.
Mekanisme dasar seputar masalah ini dijelaskan secara rinci dalam laporan bug ini dan entri blog ini.