如何讓SQL Server像MySQL一樣擁有慢查詢日誌(Slow Query Log慢日誌) SQL Server一直以來被人詬病的一個問題是缺少了像MySQL的慢日誌功能,程式員和運維無法知道資料庫過去歷史的慢查詢語句。 因為SQLServer預設是不捕獲過去歷史的長時間阻塞的SQL語句,導致大 ...
如何讓SQL Server像MySQL一樣擁有慢查詢日誌(Slow Query Log慢日誌)
SQL Server一直以來被人詬病的一個問題是缺少了像MySQL的慢日誌功能,程式員和運維無法知道資料庫過去歷史的慢查詢語句。
因為SQLServer預設是不捕獲過去歷史的長時間阻塞的SQL語句,導致大家都認為SQL Server沒有歷史慢日誌功能
其實SQLServer提供了擴展事件讓用戶自己去捕獲過去歷史的長時間阻塞的SQL語句,但是因為不是預設出廠配置並且設置擴展事件對初級用戶有一定難度,這裡可以說不得不是一個遺憾,希望後續版本的SQL Server可以預設設置好慢日誌的相關擴展事件,用初級用戶也可以快速上手。
話不多說,這個文章主要講述設置慢日誌的擴展事件的步驟,並且把慢日誌提供第三方程式讀取以提供報表功能。
擴展事件介紹
SQL Server 擴展事件(Extended Events,簡稱 XE)是從 SQL Server 2008 開始引入的一種輕量級、高度可定製的事件處理系統,
旨在幫助資料庫管理員和開發人員更好地監控、調試和優化 SQL Server 的性能。
擴展事件可以用於捕獲和分析 SQL Server 內部發生的各種事件,以便識別和解決性能瓶頸和問題。
擴展事件優點包括輕量級、統一事件處理框架和集成性。事件設計對系統性能影響最小,確保在高負載環境下也能穩定運行。
擴展事件可以與 SQL Server Profiler 和 SQL Server Audit 結合使用,為用戶提供全面的診斷和監控工具。
實驗步驟
創建環境所需的資料庫和表
--視窗1 --建表 USE testdb GO CREATE TABLE Account(id INT, name NVARCHAR(200)) INSERT INTO [dbo].[Account] SELECT 1,'Lucy' UNION ALL SELECT 2,'Tom' UNION ALL SELECT 3,'Marry' --查詢 SELECT * FROM [dbo].[Account]
創建擴展事件
輸入擴展事件名稱
不要使用模版
事件庫搜索block,選擇blocked_process_report
確認事件
選擇你需要的欄位
這裡選擇client_app_name、client_hostname、database_id、database_name、plan_handle、query_hash、request_id、session_id、sql_text欄位
當然你可以勾選自己想要的欄位,這裡只是拋磚引玉
續
直接下一步
這裡需要註意的是,擴展事件日誌不能全量保存,所以用戶需要考慮好保留多長時間的擴展事件,假設一天可以產生的擴展事件大小為1GB,那麼每個擴展事件文件大小1GB,最多5個擴展事件文件意味著你不能查詢到5天之前的數據
比如你不能查詢到前面第8天的擴展事件,擴展事件是滾動利用的。
擴展事件創建情況預覽
小提示:你可以點擊script生成這個擴展事件的create腳本,那麼其他伺服器就不用這樣用界面去創建這麼繁瑣了。
生成出來的擴展事件
CREATE EVENT SESSION [slowquerylog] ON SERVER ADD EVENT sqlserver.blocked_process_report (ACTION ( sqlserver.client_app_name, sqlserver.client_hostname, sqlserver.database_id, sqlserver.database_name, sqlserver.plan_handle, sqlserver.query_hash, sqlserver.request_id, sqlserver.session_id, sqlserver.sql_text ) ) ADD TARGET package0.event_file (SET filename = N'E:\DBExtentEvent\slowquerylog.xel') WITH ( STARTUP_STATE = ON ); GO
完成
你可以勾選
a.擴展事件創建完成之後立刻啟動
b.查看實時捕獲的數據
立刻啟動擴展事件
一定要設置locked process threshold,否則無辦法捕獲慢SQL語句,這個選項類似於MySQL的long_query_time參數
locked process threshold是SQL Server2005推出的一個選項,下麵設置阻塞10秒就會記錄
--視窗2 --locked process threshold是SQL Server2005推出的一個選項 --設置阻塞進程閾值 sp_configure 'show advanced options', 1 ; GO RECONFIGURE ; GO sp_configure 'blocked process threshold', 10 ; --10秒 GO RECONFIGURE ; GO
執行一個update語句,不要commit
--視窗3 USE testdb; GO BEGIN tran update Account set name ='Test' where ID = 2 --commit
查詢數據
-- 視窗4 USE testdb; GO -- 這個查詢會被視窗3中的事務阻塞 SELECT * FROM Account WHERE ID = 2
執行完畢之後,你可以看到擴展事件已經記錄下來了
雙擊查看詳細的會話裡面的語句
可以很清楚的看到誰是被blocked的語句,誰是主動blocking的語句也就是源頭
同時可以看到擴展事件已經記錄到xel文件
使用其他編程語言製作慢查詢日誌報表
微軟提供了使用 SQL Server Management Studio (SSMS) 和 T-SQL 查詢擴展事件 XEL 文件內容的 API。
我們可以使用 sys.fn_xe_file_target_read_file 函數來讀取 XEL 文件中的內容。
然後,你可以將這些數據導出為其他編程語言可以處理的格式
SQL語句
-- 查詢擴展事件 XEL 文件內容 SELECT event_data.value('(event/@name)[1]', 'VARCHAR(50)') AS event_name, event_data.value('(event/@timestamp)[1]', 'DATETIME2') AS event_timestamp, event_data.value('(event/data[@name="duration"]/value)[1]', 'INT') AS duration, event_data.value('(event/action[@name="client_app_name"]/value)[1]', 'VARCHAR(255)') AS client_app_name, event_data.value('(event/action[@name="client_hostname"]/value)[1]', 'VARCHAR(255)') AS client_hostname, event_data.value('(event/action[@name="database_name"]/value)[1]', 'VARCHAR(255)') AS database_name, event_data.value('(event/action[@name="sql_text"]/value)[1]', 'VARCHAR(MAX)') AS sql_text FROM sys.fn_xe_file_target_read_file('E:\DBExtentEvent\slowquerylog*.xel', NULL, NULL, NULL) AS t CROSS APPLY t.event_data.nodes('event') AS XEvent(event_data);
使用 Python 讀取 XEL 文件內容
使用 pandas 庫和pyodbc驅動程式從 SQL Server 導出數據併在 Python 中進行處理。
以下是一個示例腳本
import pyodbc import pandas as pd # 設置資料庫連接 conn = pyodbc.connect( 'DRIVER={SQL Server};' 'SERVER=your_server_name;' 'DATABASE=your_database_name;' 'UID=your_username;' 'PWD=your_password' ) # 查詢 XEL 文件內容 query = """ SELECT event_data.value('(event/@name)[1]', 'VARCHAR(50)') AS event_name, event_data.value('(event/@timestamp)[1]', 'DATETIME2') AS event_timestamp, event_data.value('(event/data[@name="duration"]/value)[1]', 'INT') AS duration, event_data.value('(event/action[@name="client_app_name"]/value)[1]', 'VARCHAR(255)') AS client_app_name, event_data.value('(event/action[@name="client_hostname"]/value)[1]', 'VARCHAR(255)') AS client_hostname, event_data.value('(event/action[@name="database_name"]/value)[1]', 'VARCHAR(255)') AS database_name, event_data.value('(event/action[@name="sql_text"]/value)[1]', 'VARCHAR(MAX)') AS sql_text FROM sys.fn_xe_file_target_read_file('E:\DBExtentEvent\slowquerylog*.xel', NULL, NULL, NULL) AS t CROSS APPLY t.event_data.nodes('event') AS XEvent(event_data); """ # 使用 pandas 讀取數據 df = pd.read_sql(query, conn) # 關閉資料庫連接 conn.close() # 顯示數據 print(df) # 將數據保存為 CSV 文件 df.to_csv('slowquerylog.csv', index=False)
這裡的一個問題是,你不能直接讀取XEL文件,本身XEL文件是一個二進位文件,必須掛接到線上SQL Server實例(任何SQL Server實例都可以,不一定是生產庫的那一臺SQL Server實例,只要是XEL文件所在的機器)
另外一個方法是使用 PowerShell 中的 Microsoft.SqlServer.XEvent.Linq.QueryableXEventData 類直接解析 XEL 文件,不用掛接到SQL Server實例
直接讀取 XEL 文件的內容,然後導出CSV文件,讓其他編程語言處理
Step 1: 創建 PowerShell 腳本 ReadXELFile.ps1
# 載入所需的程式集 Add-Type -Path "C:\Program Files\Microsoft SQL Server\140\SDK\Assemblies\Microsoft.SqlServer.XEvent.Linq.dll" # 定義XEL文件路徑 $xelFilePath = "E:\DBExtentEvent\slowquerylog*.xel" # 創建XEventData對象 $events = New-Object Microsoft.SqlServer.XEvent.Linq.QueryableXEventData($xelFilePath) # 初始化一個空數組來存儲事件數據 $eventDataList = @() # 遍歷每個事件並提取所需的欄位 foreach ($event in $events) { $eventData = New-Object PSObject -Property @{ EventName = $event.Name Timestamp = $event.Timestamp Duration = $event.Fields["duration"].Value ClientAppName = $event.Actions["client_app_name"].Value ClientHostname = $event.Actions["client_hostname"].Value DatabaseName = $event.Actions["database_name"].Value SqlText = $event.Actions["sql_text"].Value } $eventDataList += $eventData } # 將事件數據導出為CSV文件 $eventDataList | Export-Csv -Path "E:\DBExtentEvent\slowquerylog.csv" -NoTypeInformation
Step 2: Python 腳本 ReadCSVFile.py讀取導出的 CSV 文件
import pandas as pd # 定義CSV文件路徑 csv_file_path = "E:\\DBExtentEvent\\slowquerylog.csv" # 使用pandas讀取CSV文件 df = pd.read_csv(csv_file_path) # 顯示數據 print(df)
這個方法需要使用PowerShell ,對於PowerShell 不熟悉的朋友也是一個問題
總結
本文介紹了利用【SQL Server的擴展事件】捕獲慢查詢語句的功能,也就是我們常說的開源資料庫的慢日誌
另外,一定要設置“blocked process threshold”參數,否則設置了擴展事件也沒有效果
總體來說,SQL Server作為一個企業級資料庫,確實不像MySQL這種開源資料庫簡單直接
需要設置比較繁瑣的擴展事件,對新手用戶不太友好,門檻比較高,但是因為擴展事件功能非常強大
除了捕獲慢查詢語句還可以捕獲死鎖,索引缺失等性能問題,所以這個是在所難免的
參考文章
https://www.sqlshack.com/using-sql-server-extended-events-to-monitor-query-performance/
https://learn.microsoft.com/en-us/troubleshoot/sql/database-engine/performance/troubleshoot-slow-running-queries
https://erikdarling.com/monitoring-sql-server-for-query-timeouts-with-extended-events/
https://sqlmaestros.com/free-sql-video-troubleshoot-slow-running-query-sql-server-extended-events-wait-stats/
本文版權歸作者所有,未經作者同意不得轉載。