如何让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实例)

另外一个方法是使用 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这种开源数据库简单直接

需要设置比较繁琐的扩展事件,对新手用户不太友好,门槛比较高,但是因为扩展事件功能非常强大

除了捕获慢查询还可以捕获死锁,索引缺失等性能问题,所以这个是在所难免的

本文版权归作者所有,未经作者同意不得转载。

如何让SQL Server像MySQL一样拥有慢查询日志(Slow Query Log慢日志)的更多相关文章

  1. MySQL:动态开启慢查询日志(Slow Query Log)

    前言 在开发中,高效能的程序 也包括 高效能的查询,所以优化SQL也是程序员必要技能之一.要优化就必须要有慢日志记录才可以知道哪些查询慢,然后反向去修改 慢日志设置方式 写入文件 写入数据库 实践操作 ...

  2. MySQL 慢查询日志(Slow Query Log)

    同大多数关系型数据库一样.日志文件是MySQL数据库的重要组成部分.MySQL有几种不同的日志文件.通常包含错误日志文件,二进制日志,通用日志.慢查询日志.等等.这些日志能够帮助我们定位mysqld内 ...

  3. mysql中slow query log慢日志查询分析

    在mysql中slow query log是一个非常重要的功能,我们可以开启mysql的slow query log功能,这样就可以分析每条sql执行的状态与性能从而进行优化了. 一.慢查询日志 配置 ...

  4. 对Oracle 、SQL Server、MySQL、PostgreSQL数据库优缺点分析

    对Oracle .SQL Server.MySQL.PostgreSQL数据库优缺点分析 Oracle Database Oracle Database,又名Oracle RDBMS,或简称Oracl ...

  5. 通过sql server 连接mysql

    图文:通过sql server 连接mysql   1.在SQL SERVER服务器上安装MYSQL ODBC驱动; 驱动下载地址:http://dev.mysql.com/downloads/con ...

  6. 数据库 SQL Server 到 MySQL 迁移方法总结

    最近接手一起老项目数据库 SQL Server 到 MySQL 的迁移.因此迁移前进行了一些调查和总结.下面是一些 SQL Server 到 MySQL 的迁移方法. 1. 使用 SQLyog 迁移 ...

  7. atitit。mssql sql server 转换mysql 及 分页sql ast的搭建

    atitit.mssql sql server 转换mysql  及 分页sql ast的搭建 1. 主要的的转换::函数的转换,分页的转换 1 2. 思路::mssql sql >>as ...

  8. 从SQL Server到MySQL,近百亿数据量迁移实战

    从SQL Server到MySQL,近百亿数据量迁移实战 狄敬超(3D) 2018-05-29 10:52:48 212 沪江成立于 2001 年,作为较早期的教育学习网站,当时技术选型范围并不大:J ...

  9. sql server vs mysql

    1.中文: my.ini [mysqld] character-set-server=utf8 character-set-client=utf8 data\testdb\db.opt default ...

  10. SQL Server to MySQL

    使用 Navicat 导入向导迁移 会遇到以下问题 SQL Server 中的 GUID 类型字段会变成 {guid} 多个外层花括号, 导致程序问题. 部分字段类型长度不大一致, 需要手工调整. . ...

随机推荐

  1. Nodejs中间件 中间件分类和自定义中间件

    中间件 中间件理解 中间件可以理解为业务流程的中间处理环节.如生活中吃一般炒青菜,大约分为如下几步骤 express中当一个请求到达的服务器之后,可以在给客户响应之前连续调用多个中间件,来对本次请求和 ...

  2. pytest系列之-mark功能的使用

    功能使用: 标记用例,按正常.异常用例划分等级进行标记,或者按照模块进行划分. 标记后,可以执行部分用例. 例如: 你有以下用例,文件目录结构如下: testcase ----user ----man ...

  3. for while 要求选慢速的,但是for不卡,while 跟 递归 这两个容易卡

    for比while慢,但是for不卡,while跟递归容易卡 int index = 0; bool jump=flase: for( index;index==0;;)/*这个空分号算一个语句*/ ...

  4. 三维API sheder 基础

    这个shader 是靠三维数学 影响 二维像素 导致像素颜色改变 它是每个像素走一遍脚本算法 写的时候注意 语言格式 写错了 shader脚本是不能用的,根本就不好使这个 可以用区域 用xyz y为0 ...

  5. mysql windows 下配置可远程连接

    1.在防火墙入站规则里加入 3306  端口,3306 为你安装mysql 时的端口. 2.在mysql 命令行中输入: #应用mysql数据库use mysql;#将root用户可访问改成所有upd ...

  6. vue2 混入 (mixin) 带来的小惊喜

    最近在review自己写的代码时发现,在很多的地方都用了以下的代码块 1 async initCode() { 2 const resSource = await this.$API.syscode. ...

  7. 搭建第一个web项目

    实现使用: 1.创建一个普通java文件 2.Java文件的类名实现HttpServlet 3.重写service方法 4.在WEB-INF下的web.xml中添加请求与servlet类的映射关系 定 ...

  8. 2019徐州区域赛 ACEFM 题解 & pollard-rho & miller-rabin & 求出每个子树的重心 板子

    A. Cat 题目大意:你需要在 [L , R] 选取连续的一段,使得这一段的异或和小于给定的数 S. 请求出最长的长度. 做法:我们可以发现 \[(2k) \oplus (2k+1) = 1, (2 ...

  9. PyTorch程序练习(一):PyTorch实现CIFAR-10多分类

    一.准备数据 代码 import torchvision import torchvision.transforms as transforms from torch.utils.data impor ...

  10. [翻译] PySide6.QtCore.Qt.ConnectionType

    翻译 (自用,不保证对) PySide6.QtCore.Qt.ConnectionType 这个 enum 描述了 signals 和 slots 连接(connection) 的类型. 在一些特殊情 ...