【Python】如何让SQL Server像MySQL一样拥有慢查询日志(Slow Query Log慢日志)

news2024/12/23 10:53:59

如何让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自带审计功能,但有时候捕捉某些SQL比较困难,我们借助扩展事件更加精准捕捉有问题的SQL语句

有一个场景是,系统用户反馈某个功能的数据每隔几天就会被“恢复”一次,这个恢复操作由一个更新语句所触发,由于不定时发生,所以很难捕捉实际情况。项目负责人遍历整个代码之后发现代码没有包含这个更新语句,怀疑某个版本升级过程完整更新导致在服务器的某个服务中残留代码。要完成这个工作,全面捕捉所有DML语句是不现实的,非常高的QPS加上不定期执行会带来困难。

这时候可以使用扩展事件来处理这个问题

在测试数据库下创建一个test表(只有一个ID字段,这里不演示了),然后创建一个扩展事件来监控SQL文本为update test的语句,把捕捉结果存储在文件里面,执行更新语句后,查询结果

\--创建事件会话
IF EXISTS (SELECT \* FROM sys.server\_event\_sessions WHERE name \= 'CaptureSQL')
\-- 如果已有则删除事件会话
DROP EVENT SESSION \[CaptureSQL\] ON SERVER
GO
\-- 创建名为CaptureSQL的事件会话
CREATE EVENT SESSION \[CaptureSQL\] ON SERVER
\-- 添加sql\_statement\_starting和sql\_statement\_completed的跟踪,并且对sql\_text列进行筛选,同时为了减少开销,还指定了数据库名
-- 在Action中通常添加我们需要跟踪的内容
ADD EVENT sqlserver.sql\_statement\_starting(
    ACTION(sqlserver.client\_app\_name, sqlserver.client\_connection\_id,
    sqlserver.client\_hostname, sqlserver.client\_pid, sqlserver.database\_id,
    sqlserver.nt\_username, sqlserver.sql\_text, sqlserver.username)
    WHERE ((sql\_text like '%update&test%') AND (\[sqlserver\].\[database\_name\]\=(N'AdventureWorks2016')))  \--关键这一句,捕捉update test语句
),
ADD EVENT sqlserver.sql\_statement\_completed(
    ACTION(sqlserver.client\_app\_name, sqlserver.client\_connection\_id,
    sqlserver.client\_hostname, sqlserver.client\_pid, sqlserver.database\_id,
    sqlserver.nt\_username, sqlserver.sql\_text, sqlserver.username)
    WHERE ((sql\_text like '%update&test%')) AND (\[sqlserver\].\[database\_name\]\=(N'AdventureWorks2016'))
)
\-- 把会话数据保存到文件中以便日后查看
ADD TARGET package0.event\_file(
    SET filename\=N'E:\\SQLData\\CaptureSQL.xel',
    METADATAFILE \= N'E:\\SQLData\\CaptureSQL.xem'
)
WITH (STARTUP\_STATE\=ON) \-- 指定随着服务器启动而启用,服务器宕机后能自动继续运行
GO
\-- 创建完后启用会话,因为默认会话是不开启的
ALTER EVENT SESSION \[CaptureSQL\] ON SERVER STATE \= START;
GO

查询结果
;WITH ee\_data AS
(
    SELECT data \= CONVERT(XML, event\_data)
    FROM sys.fn\_xe\_file\_target\_read\_file(
        N'E:\\SQLData\\CaptureSQL.xel', \-- 注意替换实际路径
        N'E:\\SQLData\\CaptureSQL.xem', \-- 注意替换实际路径
        NULL, NULL
    )
),
tab AS
(
    SELECT
        \[host\] \= data.value('(/event/action\[@name="client\_hostname"\]/value)\[1\]', 'nvarchar(400)'),
        app\_name \= data.value('(/event/action\[@name="client\_app\_name"\]/value)\[1\]', 'nvarchar(400)'),
        username \= data.value('(/event/action\[@name="username"\]/value)\[1\]', 'nvarchar(400)'),
        \[object\_name\] \= data.value('(/event/data\[@name="object\_name"\]/value)\[1\]', 'nvarchar(250)'),
        \[timestamp\] \= data.value('(/event/@timestamp)\[1\]', 'datetime2'),
        \[statement\] \= data.value('(/event/action\[@name="sql\_text"\]/value)\[1\]', 'nvarchar(400)'),
        \[DBName\] \= DB\_Name(data.value('(/event/action\[@name="database\_id"\]/value)\[1\]', 'nvarchar(400)')),
        \[ClientPid\] \= data.value('(/event/action\[@name="client\_pid"\]/value)\[1\]', 'nvarchar(400)')
    FROM ee\_data
)
SELECT DISTINCT \[host\], app\_name, username, MAX(\[timestamp\]) as last\_executed,
    \[object\_name\], \[statement\], \[DBName\], ClientPid
FROM tab
GROUP BY \[host\], app\_name, username, \[object\_name\], \[statement\], \[DBName\], ClientPid;

创建完毕之后,我们可以使用简单的UPDATE TEST SETID=1语句可触发事件。

通过这种简单的审计方法,让捕捉SQL语句更加简单


总结

本文介绍了利用【SQL Server的扩展事件】捕获慢查询语句的功能,也就是我们常说的开源数据库的慢日志

另外,一定要设置**“blocked process threshold**”参数,否则设置了扩展事件也没有效果

总体来说,SQL Server作为一个企业级数据库,确实不像MySQL这种开源数据库简单直接

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

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

👉 这份完整版的Python全套学习资料已经上传,朋友们如果需要可以扫描下方二维码免费领取【保证100%免费】
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2200820.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

inBuilder低代码平台新特性推荐-第二十五期

今天来给大家带来的是inBuilder低代码平台社区版中的特性推荐系列第二十五期——选人组件扩展! 一、概述 inBuilder低代码平台社区版的开发过程中,选人组件支持tab页中增加扩展页面,由二开人员根据业务场景实现自定义取数接口和页面展示形式…

【笔记】济南,天命人,春秋

孤独而高傲的济南人 浩克山东知天命热爱的sensei 浩克山东 哦哦,最高的大葱也是济南的了,这大葱,比一般人要高呢,尽管济南的朋友们也都个子不矮。。能想像的到两米高的米库。。。。 然而在这块地界,遇到个人&#xf…

基于STM32的简易交通灯proteus仿真设计(仿真+程序+设计报告+讲解视频)

基于STM32的简易交通灯proteus仿真设计(仿真程序设计报告讲解视频) 仿真图proteus 8.9 程序编译器:keil 5 编程语言:C语言 设计编号:C0091 **1.**主要功能 功能说明: 以STM32单片机和数码管、LED灯设计简易交通…

版本控制系统Helix Core的常见使用误区及解决办法、实用工具及新功能介绍

日前,Perforce携手合作伙伴龙智一同亮相Unreal Fest 2024上海站,分享Helix Core版本控制系统及其协作套件的强大功能与最新动态,助力游戏创意产业加速前行。 Perforce解决方案工程师Kory Luo在活动主会场,带来《Perforce Helix C…

QT安装成功后-在创建项目时,发现仅有项目名文件

(1)QT安装成功后,发现仅有项目名文件其他可编辑文件缺失 (2)点击文件名左上角的感叹号显示【No kits are enabled for this project. Enable】 小编在尝试多次后发现,可以通过以下方式解决:QT软…

YOLO11改进|编码器篇|引入AIFI混合特征编码器

目录 一、【AIFI】混合编码器机制1.1【AIFI】混合编码器介绍1.2【AIFI】核心代码 二、添加【AIFI】机制2.1STEP12.2STEP22.3STEP32.4STEP4 三、yaml文件与运行3.1yaml文件3.2运行成功截图 一、【AIFI】混合编码器机制 1.1【AIFI】混合编码器介绍 【AIFI】在论文中并没有结构图…

CVPR 2024最佳论文候选-pixelSplat论文解读

目录 一、概述 二、相关工作 1、单场景下的视角合成 2、基于先验的三维重建和视图合成 3、多视图几何测量 三、3DGS的缺点 1、容易陷入最小值 2、需要大量输入图像 3、尺度模糊性 四、pixelSplat 1、解决尺度模糊性(深度信息生成) 2、编码器…

QT实现QMessageBox中文按钮

这是我记录Qt学习过程心得文章的第二篇,主要是为了方便QMessageBox弹出框的使用,通过自定义的方式,将其常用的功能,统一封装成一个函数,还是写在了Skysonya类里面。 实现代码: //中文提示对话框 bool Sky…

线程(四)线程的同步——条件变量

文章目录 线程线程的同步和互斥线程同步--条件变量什么是线程同步示例--条件变量的使用示例--使用两个线程对同一个文件进行读写示例--一个读者一个写者使用条件变量来实现同步 线程 线程的同步和互斥 线程同步–条件变量 是一个宏观概念,在微观上包含线程的相互…

新160个crackme - 078-CodeZero.1

运行分析 需要破解Serial PE分析 VB程序,32位,无壳 静态分析&动态调试 使用VB Decompiler进行分析找到check按钮事件: Form1 -> Command1_Click_4055F4发现直接爆出了Serial55555 验证成功

【xilinx-versal】【Petalinux】I2C驱动开发问题记录

问题 调试中发现系统起来后无I2C设备。 仔细查找后发现没有配置versal的I2C控制器。 解决方法 打开versal的I2C控制器的配置 起来后I2C设备注册成功

Acwing 区间问题

Acwing 905.区间选点 实现思路: 将每个区间按照右端点从小到大排序从前往后依次枚举每个区间 若当前区间中已经包含点,则跳过;否则(即当前区间的左端点大于该点),选择当前区间的右端点; 证明&a…

设计模式:单例

一.什么是单例模式 单例模式是一种设计模式,指在整个程序生命周期中有且仅有一个实例的类。可以分为懒汉式以及饿汉式。 懒汉式:只有在类的实例被使用时才生成唯一实例。但是存在线程安全以及内存泄露的问题。可以节省系统资源。 饿汉式:程序…

《Oracle DB备份与恢复》:一文千字教你掌握备份基础知识

** List item 备份需要扎实掌握基础知识,这样才能规划好适合自己的备份恢复策略,才能在出故障的时候不慌不忙,从容应付。 好了不多逼逼了,直接上干货。** 1. 备份分类: 备份根据性质和目的不同分为以下几种&#…

车辆路径规划问题(VRP)优化方案

车辆路径规划问题(VRP)优化方案 车辆路径规划问题(Vehicle Routing Problem, VRP)是物流领域中一个经典的组合优化问题,目标是在满足客户需求的情况下,找到一组车辆的最优配送路径,以最小化总的…

如何让员工意识到六西格玛项目对公司和个人的长期利益?

当下,六西格玛作为一种以数据驱动的管理方法论,正逐步成为许多企业实现卓越运营的重要工具。然而,要让员工深刻认识到六西格玛项目不仅对公司长远发展至关重要,也对他们个人职业生涯有着深远的积极影响,并非易事。下面…

C++ day05(模版与容器)

目录 【1】模版 template 1》概念 2》函数模版 3》类模版 【2】容器 1》STL标准模版库 2》容器的概念 3》顺序容器 1> arrry(C11) 2> vector 3> list 4> deque 4》 关联容器 5》迭代器 iterator 【1】模版 template 1》概念 C模版可以让类或函数声…

javacpp调用pdfium的c++动态库

1、.h头文件 2、生成java代码的conf PdfiumDocumentConfigure.java package org.swdc.pdfium.conf;import org.bytedeco.javacpp.annotation.Platform; import org.bytedeco.javacpp.annotation.Properties; import org.bytedeco.javacpp.tools.InfoMap; import org.byte…

网络知识点之—EVPN

EVPN(Ethernet Virtual Private Network)是下一代全业务承载的VPN解决方案。EVPN统一了各种VPN业务的控制面,利用BGP扩展协议来传递二层或三层的可达性信息,实现了转发面和控制面的分离。 EVPN解决传统L2VPN的无法实现负载分担、…

springboot+vue前后端分离-使用腾讯云服务器部署网站

项目打包 参考链接 CSDN springboot打包 idea默认新建的shell窗口在项目根目录位置,可以看到项目根目录下有mvnw HELP.md log mvnw mvnw.cmd pom.xml src target./mvnw clean package -Dmaven.test…