
大家估计都经历过这样的“紧张时刻”:
周一早上刚到公司,运维群里突然炸锅:“生产环境数据库CPU飙升到100%了!”、“系统响应极慢,接口大量超时!”、“前端页面直接白屏了!”……
打开监控一看,好家伙,数据库里堆积了几百个执行时间超过几分钟的慢查询。这些“流氓SQL”不仅占满了数据库连接池,还疯狂消耗CPU资源,导致正常的业务请求根本挤不进去。
面对这种“慢SQL风暴”,手动一条条去KILL显然来不及。今天,我们就来分享一个实战技巧:如何用Python写一个轻量级的“慢SQL自动查杀脚本”,定时清理垃圾会话,为数据库“止血”!需要的同学可以联系我获取完整脚本。
一、核心思路:监控+筛选+查杀
我们的目标很明确:在后台默默运行,每隔一段时间检查一次数据库,发现符合条件的“坏分子”就直接干掉。
整体逻辑分为三步:
二、实战拆解与避坑指南
在编写这个脚本的过程中,有几个极易踩坑的技术点,这里特意把核心代码片段拎出来给大家讲讲。
1. 如何精准揪出“慢SQL”?
我们需要查询SQL Server的动态管理视图。这里有一个非常关键的细节:获取SQL文本时,一定要做类型转换!
-- 核心查询片段
SELECT s.session_id, DATEDIFF(MINUTE, r.start_time, GETDATE()) AS duration_minutes,
CAST(t.text AS NTEXT) AS sql_text -- 重点:强转为NTEXT
FROM sys.dm_exec_sessions s
INNER JOIN sys.dm_exec_requests r ON s.session_id = r.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE s.is_user_process = 1
AND DATEDIFF(MINUTE, r.start_time, GETDATE()) >= 20 -- 运行超过20分钟
AND t.text LIKE '%select%' -- 包含特定关键词避坑点:如果不将t.text强转为NTEXT类型,Python的pyodbc驱动默认只会截取前255个字符。到时候你查杀了会话,却在日志里看不到完整的SQL语句,排查问题时就会一脸懵。
2. 为什么执行KILL命令会报错?
很多同学可能和我一样,在写好查杀逻辑cursor.execute("KILL 55")后,运行脚本却抛出了异常:“无法在用户事务内部使用KILL命令”。

这是因为pyodbc默认开启事务模式,而KILL这种系统级命令是不能包裹在普通事务里的。
解决方法:在建立数据库连接后,开启自动提交模式。
conn = pyodbc.connect(conn_str)
conn.autocommit = True # 开启自动提交,让KILL命令立即生效3. 完整的查杀与日志记录
当脚本抓到“现行”后,不仅要杀掉它,还要把“案发现场”记录下来。
# 查杀逻辑片段
kill_sql = f"KILL {session_id}"
cursor.execute(kill_sql)
# 记录完整SQL到日志,方便后续甩锅...啊不,复盘
log_msg = (f"成功杀掉会话! SessionID: {session_id}, "
f"运行时长: {duration}分钟\n"
f"执行的SQL语句:\n{full_sql_text}")
logging.warning(log_msg)
三、总结与建议
这个脚本虽然没有多少行代码,但在生产环境紧急救火时非常管用。它可以作为一个守护进程在后台运行,充当数据库的“保安”。
最后给几点生产环境的使用建议:
希望这个小工具能帮大家远离半夜被报警电话叫醒的烦恼!如果你觉得有用,欢迎点赞、在看、转发三连!🚀