使用WinDbg调试SQL Server查询
上一篇文章我给你介绍了WinDbg的入门,还有你如何能附加到SQL Server。今天的文章,我们继续往前一步,我会向你展示使用WinDbg调试SQL Server查询需要的步骤。听起来很有意思?我们开始吧!
假设在你面前有个简单的查询,你想在WinDbg里调试那个特定的查询。听起来很简单,但一旦你开始考虑这个问题,就会碰到很多问题:
- 在我特定执行的查询上,我如何标识出正确的工作者线程?
- 在sqlservr.exe里,我应该在哪里设置断点?
我们来具体讲解下这2个问题。
标识出正确的工作者线程
当你在SQL Server里执行一个查询,默认情况下你是不知道查询是在哪个线程上运行的。幸运的是SQL Server在DMV sys.dm_os_threads里提供os_thread_id列来告诉我们。OS线程ID就是用来执行指定查询的。不幸的是你需要从sys.dm_exec_requests直到sys.dm_os_threads连接多个表才可以得到需要的信息。我们来看下面的查询:
SELECT R.Session_Id, Th.os_thread_id FROM sys.dm_exec_requests R
JOIN sys.dm_exec_sessions S ON R.session_id = S.session_id
JOIN sys.dm_os_tasks T ON R.task_address = T.task_address
JOIN sys.dm_os_workers W ON T.worker_address = W.worker_address
JOIN sys.dm_os_threads Th ON W.thread_address = Th.thread_address
WHERE S.is_user_process = 1
GO
在WinDbg里用CTRL+BREAK中断sqlservr.exe。为了切换到sys.dm_os_thread提供的系统线程ID,你可以用下列WinDbg命令:
~~[tid]s
占位符tid的值就是实际的系统线程ID——16进制值。因此你需要来自sys.dm_os_thread的os_thread_id列值转为16进制值,用刚才提到的命令。当你的系统线程ID是4910时,你应该用下列WinDbg命令切换到正确的线程:
~~[132E]s
当你的查询运行时,对于你的产寻,sys.dm_os_thread只显示系统线程ID。因此就有下一个问题:对于一个执行的查询,我如何获得“正确的”系统线程ID。我这里用一个小技巧:首先我运行一个简单的WAITFOR DELAY命令(例如1分钟),然后再运行实际的查询。如果你用这个方法,你需要保证在1个批处理里提交2个T-SQL查询。不然的话,SQL OS调度会放置WAITFOR语句和实际的查询在2个不同的线程!我们来看实际的代码:
WAITFOR DELAY '00:01:00' SELECT
soh.*,
d.*
FROM Sales.SalesOrderHeader soh
INNER JOIN Sales.SalesOrderDetail d ON soh.SalesOrderID = d.SalesOrderID
WHERE soh.SalesOrderID = 71832
AND d.SalesOrderDetailID = 111793
GO
在等待期间,你需要进行下列操作:
- 从sys.dm_os_thread为你等待的查询获得在不同会话里系统线程ID
- 转化系统线程ID为16进制值
- 用CTRL+BREAK中断sqlservr.exe
- 用~~[tid]命令切换到正确的系统线程ID
- 在指定线程上设置断点
- 继续sqlservr.exe的运行
- 等待直到触发断点
你要在用WAITFOR DELAY语句引起的延迟时间内完成所有这些操作。如果超过这个时间,这个方法就不可靠了。因此在刚开始的时候,你可以用WAITFOR DELAY设置长一点的延迟时间,直到用这个方法你已经有经验了。
在sqlservr.exe里设置“好的”断点
现在你已经从sys.dm_os_thread获得了系统线程ID,而且你用WinDbg挂起了sqlservr.exe的执行。下一步你要在sqlservr.exe里设置断点,这样的话你可以在你的查询里调试并单步执行通过。但什么是好的断点呢?这个看情况:)执行计划里的每个运算符都是用独立的C++类实现的,它里面包含不同的函数。其中一个熟知的函数是GetRow,它返回一行到执行里上迭代器。我的方法如下:在执行计划里,尝试在最左的一个迭代器里设置断点。从我的经验里发现,每个SELECT查询开始于sqlmin!CQueryScan::GetRow的函数调用。
刚开始在指定类和函数上设置断点应该非常有用。当然你需要花很长时间(当单步执行通过代码时),指导你碰到SQL Server有意思的部分,像B树管理器,或者闩锁/旋转锁的实现。但初次试验时,建议你在特定函数设置断点就可以了。你要确保断点设置在正确的线程上,因为你只想调试你特定查询,没别的!用bm命令在指定线程和符号名上设置断点:
~tid bm sqlmin!CQueryScan::GetRow
但你还要意识到你不必提供系统线程ID。bm命令期望一个从零开始数字线程号。当你用~~[132E]s切换到正确的系统线程时,你会在WinDbg左下角看到线程号:

当WinDbg提示像47的线程号,你可以用下列命令在正确的线程上,在sqlmin!CQueryScan::GetRow函数设置断点:
~47 bm sqlmin!CQueryScan::GetRow
设置断点后,你可以用F5继续sqlservr.exe的运行。几秒后(取决于在WAITFOR语句上设置的延迟)WinDbg应该会在特定的断点中断:

现在好戏才开始:你可以用k命令探索当前的调用堆栈,你可以对汇编代码单步执行通过,看看其他函数是如何调用的。梦想有多远,你的选择就有多远(Your choices are endless, and only limited by your imagination.)。
小结
希望这篇文章已经给你以下内容深入的介绍:
在sqlservr.exe里对于指定的查询进行调试时,如何成功的设置断点。
请继续关注并玩“坏”WinDbg!
感谢关注!
参考文章:
https://www.sqlpassion.at/archive/2014/05/13/debugging-a-sql-server-query-with-windbg/
使用WinDbg调试SQL Server查询的更多相关文章
- 如何设断点????-----使用WinDbg调试SQL Server查询
http://www.cnblogs.com/woodytu/p/4665427.html http://www.sqlservercentral.com/blogs/aschenbrenner/20 ...
- 使用WinDbg调试SQL Server——入门
这篇文章我想探究下SQL Server里完全不同的领域:如果使用WinDbg(来自针对Windows的调试工具)调试SQL Server.在我们进入枯涩细节之前,我想详细解释下为什么选择这样晦涩的话题 ...
- 使用WinDbg调试SQL Server——入门:Woodytu
http://www.cnblogs.com/woodytu/p/4663525.html https://www.sqlpassion.at/archive/2014/05/13/debugging ...
- Windbg调试Sql Server 进程
http://blog.csdn.net/bcbobo21cn/article/details/52261466 http://www.sqlservercentral.com/blogs/asche ...
- 数据库表设计时一对一关系存在的必要性 数据库一对一、一对多、多对多设计 面试逻辑题3.31 sql server 查询某个表被哪些存储过程调用 DataTable根据字段去重 .Net Core Cors中间件解析 分析MySQL中哪些情况下数据库索引会失效
数据库表设计时一对一关系存在的必要性 2017年07月24日 10:01:07 阅读数:694 在表设计过程中,我无意中觉得一对一关系觉得好没道理,直接放到一张表中不就可以了吗?真是说,网上信息什么都 ...
- [转] 利用SET STATISTICS IO和SET STATISTICS TIME 优化SQL Server查询性能
首先需要说明的是这篇文章的内容并不是如何调节SQL Server查询性能的(有关这方面的内容能写一本书),而是如何在SQL Server查询性能的调节中利用SET STATISTICS IO和SET ...
- SQL SERVER 查询性能优化——分析事务与锁(五)
SQL SERVER 查询性能优化——分析事务与锁(一) SQL SERVER 查询性能优化——分析事务与锁(二) SQL SERVER 查询性能优化——分析事务与锁(三) 上接SQL SERVER ...
- SQL Server 查询性能优化 相关文章
来自: SQL Server 查询性能优化——堆表.碎片与索引(一) SQL Server 查询性能优化——堆表.碎片与索引(二) SQL Server 查询性能优化——覆盖索引(一) SQL Ser ...
- 利用SET STATISTICS IO和SET STATISTICS TIME 优化SQL Server查询性能
首先需要说明的是这篇文章的内容并不是如何调节SQL Server查询性能的(有关这方面的内容能写一本书),而是如何在SQL Server查询性能的调节中利用SET STATISTICS IO和SET ...
随机推荐
- C#中服务端接受前端JSON字符串转换成字典集合
我们是否可以把从前端接受的JSON字符串转换成字典集合呢? 比如从前端接收:{'size':'10', 'weight':'10kg'} 在服务端转换成:[{size:"10"}, ...
- 闲暇时间开发的个人app
最近一段时间公司不是很忙,晚上基本没怎么加班.所以自己利用晚上在家的时间开发了一个app(奇趣营),其实自从转android开发以来,就有想过要自己开发一个app.一方面可以提升自己的经验:另一方面可 ...
- THEOS makefile
转自https://www.h4ck.org.cn/2013/07/theos-makefile/ theos的makefile写法与其他linux/unix环境下的makefile写法大同小异,但是 ...
- Scala深入浅出实战经典之 List的foldLeft、foldRight、sort操作代码实战
Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 腾讯微云:http://url.cn/TnGbdC 3 ...
- nodejs express 框架解密1-总体结构
本文是基于express3.4.6的. 1.express 代码结构为: bin/express 是在命令行下的生成express 框架目录文件用的 lib/express 是框架的入口文件 lib/ ...
- 【转】Windows Phone 8 开发环境的搭建
1.先安装Microsoft Visual Studio 2012旗舰版,安装包自己下载. 系统必须是Win8 X64 对于软硬件的检测可以参照: Windows Phone 8开发环境搭建之一.电脑 ...
- <《基金经理投资笔记丛书4-1:投资是一种生活方式》>
在中国股市每年能获得10%的收益已经是非常好了,但问题是大多数股民不认为这是一个很高的收益水平,尽管现实中大多数股民的收益状况比这要差很多. 投资中一个重要的心理陷阱是过度自信,过度自信的一个主要表现 ...
- Ecshop文章列表页显示内容摘要
本教程中讲到的“内容摘要”指的是文章内容的前 60个字符(当然也可以是前40个,前50个等等) 下面以 2.7.2版 + 官方默认模板 为例进行讲解: 1).修改 includes/lib_artic ...
- LTE工作过程
LTE工作过程 一.LTE开机及工作过程如下图所示: 二.小区搜索及同步过程 整个小区搜索及同步过程的示意图及流程图如下: 1) UE开机,在可能存在LTE小区的几个中心频点上接收信号(PSS), ...
- NSXMLParser读取XML文件并将数据显示到TableView上
关于XML,有两种解析方式,分别是SAX(Simple API for XML,基于事件驱动的解析方式,逐行解析数据,采用协议回调机制)和DOM(Document Object Model ,文档对象 ...