如何让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. Qt-FFmpeg开发-保存视频流裸流(11)

    音视频/FFmpeg #Qt Qt-FFmpeg开发-保存视频流裸流 目录 音视频/FFmpeg #Qt Qt-FFmpeg开发-保存视频流裸流 1.概述 2.实现效果 3.FFmpeg保存裸流代码流 ...

  2. CENTOS6.8 修改主机名

    1.临时修改主机名   显示主机名:spark@master:~$ hostnamemaster修改主机名:spark@master:~$ sudo hostname hadoopspark@mast ...

  3. Vue3组件通信方式

    Vue3组件通信方式 不管是vue2还是vue3,组件通信方式很重要,不管是项目还是面试都是经常用到的知识点. 比如:vue2组件通信方式 props:可以实现父子组件.子父组件.甚至兄弟组件通信 自 ...

  4. 地址栏hash模式以?问号分割也可以分割的

    可以看到href里面hash没有? 但是还是以?分割了 就很不明白 但是我就indexof判断有没有? 再进行下一步逻辑 这里记录一下坑

  5. Kali Linux 终端字体配色

    在用root用户登录Kali Liunx时,会发现终端的字体无配色,非常难看,以下这幅图便是kali用户和root用户的区别,看着真难受. echo $PS1,这便是区别所在. 那我们怎么让root用 ...

  6. categraf托管与自升级

    categraf支持多种方式进行部署.托管,社区里部署和管理categraf也是五花八门,大家自己使用方便即可. 之前我们觉得大家通过ansible之类的工具批量下发/更新就能很简单地完成任务,最近很 ...

  7. filebeat实战

    1.打开filebeat支持nginx模块 [root@es-node1 /etc/filebeat]#ls fields.yml filebeat.reference.yml filebeat.ym ...

  8. 三月二十四日 安卓app打卡开发日志

    目前打卡系统基本完成 没有实现的功能有无法统计次数 和 连接本地数据库 我全程连接的远程数据库 package com.example.test_four.utils; import java.sql ...

  9. 04-Python文件操作

    打开文件 f=open("我的文件.txt","r",encoding="utf8") #打开一个文件(读模式) f.close() #关闭 ...

  10. 使用sqlcel导入数据时出现“a column named '***' already belongs to this datatable”问题的解决办法

    我修改编码为GBK之后,选择导入部分字段,如下: 这样就不会出现之前的问题了,完美 ----------------------------------------------- 但是出现一个问题,我 ...