http://tommwq.tech/blog/%e4%bd%bf%e7%94%a8%e6%89%a9%e5%b1%95%e4%ba%8b%e4%bb%b6%e8%ae%b0%e5%bd%95-sql-%e6%89%a7%e8%a1%8c%e5%8e%86%e5%8f%b2/
擴展事件(XEvent)是 SQL Server 從 2008 版本開始提供的一種記錄系統運行事件的機制。使用擴展事件可以瞭解 SQL Server 的內部執行情況,其中就包括了執行過哪些 SQL 語句。要記錄和查看 SQL 語句執行歷史,需要執行 4 個步驟:創建擴展事件會話;啓動擴展事件會話;讀取 xel 文件;關閉擴展事件會話。
1 創建擴展事件會話
IF EXISTS (SELECT * FROM sys.server_event_sessions WHERE name='test_event_session') DROP EVENT SESSION test_event_session ON SERVER; GO CREATE EVENT SESSION test_event_session ON SERVER ADD EVENT sqlserver.sql_statement_completed ( ACTION (sqlserver.sql_text) ) ADD TARGET package0.event_file ( SET filename=N'Z:\test_event_session.xel' ) WITH ( MAX_MEMORY=16MB, MAX_EVENT_SIZE=16MB, MAX_DISPATCH_LATENCY=1 SECONDS ); GO
使用語句 CREATE EVENT SESSION 可以創建擴展事件會話。要使用擴展事件記錄 SQL 執行歷史,首先必須創建擴展事件會話。這裏我們選擇 test_event_session 作爲會話名,並將 sqlserver.sql_statement_completed 事件添加到會話中。sql_statement_completed 是事件名,表示“Transact-SQL 語句已完成時發生。”事件。sqlserver 是包名,事件是從屬於某個包的。後面我們會進一步介紹包、事件等概念。擴展事件中定義了很多事件類型,這些事件可以通過下面的 SQL 語句查詢:Listing 1: 查詢 SQL Server 支持的擴展事件
SELECT packages.name,packages.description,objects.name,objects.description FROM sys.dm_xe_objects objects LEFT JOIN sys.dm_xe_packages packages ON packages.guid=objects.package_guid WHERE object_type='event' ORDER BY packages.name,objects.name
這裏我們只關注 SQL 執行歷史記錄,因此只需要添加 sql_statement_completed 事件。
當事件發生後,事件被髮送給目標(target),目標是保存事件信息的地方。這裏我們使用 event_file,表示將事件信息保存到文件中。要注意的時,參數 filename 必須以“.xel”結尾。每個目標支持不同的參數,這些參數可以通過下面的 SQL 查詢:Listing 2: 查詢目標參數
SELECT object_name,name,type_name,column_value,description FROM sys.dm_xe_object_columns WHERE column_type='customizable'
2 啓動擴展事件會話
擴展事件會話創建後,我們還需要啓動會話,讓 SQL Server 開始記錄事件。 #+caption 啓動擴展事件會話
ALTER EVENT SESSION test_event_session ON SERVER STATE=START
會話啓動之後,我們可以從下面個視圖中查詢會話的信息。Listing 3: 查詢會話信息
SELECT * FROM sys.server_event_sessions; GO SELECT * FROM sys.dm_xe_sessions; GO
3 讀取 xel 文件
啓動會話後,SQL Server 會將事件信息保存到 xel 文件中。SQL Server 不會向我們設置的 filename 文件中寫入數據,實際的文件名是在 filename 中添加序號和時間戳得到的。這麼做是爲了進行文件輪轉。在我的服務器(SQL Server 2014 SP2)上,默認情況下 SQL Server 爲每個事件會話保留最多 5GB 事件數據。這是可以配置的,方法參考上一節。
由於實際文件名不是 filename 參數值,我們需要查詢文件名。Listing 4: 查看會話 xel 文件實際名稱
SELECT n.value('(File/@name)[1]', 'nvarchar(max)') AS xel_filename FROM ( SELECT CAST(targets.target_data AS XML) AS target_data FROM sys.dm_xe_session_targets AS targets JOIN sys.dm_xe_sessions AS xe_sessions ON xe_sessions.address=targets.event_session_address JOIN sys.server_event_sessions se_sessions ON se_sessions.name=xe_sessions.name WHERE xe_sessions.name='test_event_session' ) td CROSS APPLY td.target_data.nodes('EventFileTarget') AS q(n)
得到 xel 實際文件名之後,我們可以查詢其中記錄的時間信息。這裏我們只關心 SQL 執行歷史。Listing 5: 從 xel 文件查詢事件信息
SELECT n.value('(@timestamp)[1]', 'datetime2') AS [utc_timestamp], n.value('(data[@name="statement"]/value)[1]', 'nvarchar(max)') AS statement FROM ( SELECT CAST(event_data AS XML) AS event_data FROM sys.fn_xe_file_target_read_file('Z:\test_event_session_0_132871334271260000.xel', null, null, null) ) ed CROSS APPLY ed.event_data.nodes('event') AS q(n)
4 停止會話
查詢完畢後不要忘了停止會話,以免產生性能損耗。Listing 6: 停止會話
ALTER EVENT SESSION test_event_session ON SERVER STATE=STOP
會話停止以後,對 SQL Server 沒有任何性能影響。當然如果不再需要使用這個會話,最好在會話停止後刪除會話。Listing 7: 刪除會話
DROP EVENT SESSION test_event_session ON SERVER;