Debugging a SQL Server query with WinDbg
Debugging a SQL Server query with WinDbg
In my last blog posting I gave you a general introduction to WinDbg, and told you how you can attach the debugger to SQL Server. In today’s blog posting, we will go into a little more detail, and I will show you the steps you need to live debug a SQL Server query with WinDbg. Sound interesting to you? Let’s start!
Imagine you have a simple SQL query in front of you, and you want to debug that specific query within WinDbg. Sounds like a trivial task, but as soon as you start thinking about it, various questions arise:
- How can I identify the correct worker thread within WinDbg, on which my specific query is executed?
- Where within sqlservr.exe should I set a breakpoint?
Let’s concentrate on both questions in a little bit more detail.
Identifying the correct worker thread
When you execute a query within SQL Server, you have by default no idea which thread that query runs on. Fortunately SQL Server provides us with column os_thread_id in the DMVsys.dm_os_threads. That’s the ID of the OS thread that executes a specific query. Unfortunately you need to join between multiple tables to get from sys.dm_exec_requestsdown to sys.dm_os_threads. Let’s have a look at the following query.
1
2
3
4
5
6
7
|
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
|
sqlservr.exe with WinDbg (CTRL + BREAK). To switch to a specific thread based on the OS thread ID thatsys.dm_os_threads reports, you can use the following WinDbg command:
~~[tid]s
The place holder value tid is the actual OS thread ID – as a hex value. Therefore you have to convert the value of the column os_thread_id from sys.dm_os_threads to a hex value, and use it with the above mentioned command. When your OS thread ID is 4910, you would use the following WinDbg command to switch to the correct thread:
~~[132E]s
sys.dm_os_threads only shows you the OS thread ID for your query, when your query is running. Therefore the next question arises: how can I get the *current* OS thread ID for an executing query? I’m using here a simple trick here: in the first step I’m running a simple WAITFOR DELAYcommand (e.g. 1 minute), and afterwards I’m running the actual query. If you use this approach, you have to make sure to submit both T-SQL queries to SQL Server within 1 batch. Otherwise the SQL OS scheduler may put the WAITFORstatement and your actual query on 2 different threads! Let’s have a look at the actual code:
1
2
3
4
5
6
7
8
9
10
|
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
|
During the wait interval you have to perform the following actions:
- Retrieve in a different session the OS thread ID for your (waiting) query from sys.dm_os_threads
- Convert the OS thread ID to a hex value
- Break sqlservr.exe with CTRL + BREAK
- Switch to the correct OS thread with the command ~~[tid]s
- Set a breakpoint on the specific thread
- Continue the execution of sqlservr.exe
- Wait until the breakpoint is reached
You have to perform all these actions within the delay that you are causing with the WAITFOR DELAY statement. If you take longer, that approach will not work reliably. Therefore I sugest that you wait a little bit longer in the beginning with the WAITFOR DELAY statement, until you have some experience with that approach.
Setting a “good” breakpoint within sqlservr.exe
You have now retrieved the OS thread ID fromsys.dm_os_threads, and you have suspended the execution ofsqlservr.exe with WinDbg. In the next step you have to set a breakpoint within sqlservr.exe, so that you can debug and single-step through your query. But what is a good break point? It depends ;-). Every operator in an execution plan is implemented as a separate C++ class, which contains different functions. One well-known function is GetRow, which returns one row to the upstream iterator in the execution. My approach is the following one: trying to set a breakpoint in one of the left-most iterators in the execution plan. As far as I have seen from my experiments, every SELECT query starts with a function call tosqlmin!CQueryScan::GetRow.
Setting a breakpoint on that specific class and function should work very well for the beginning. Of course it will take you a very long time (when single-stepping through the code) until you hit interesting parts of the SQL Server Engine, like the B-Tree Manager, or the Latching/Spinlocking implementation. But for the first few experiments you should be fine with a breakpoint on that specific function. You have to make sure to set the breakpoint on the correct thread because you just want to debug your specific query, and nothing else! Setting a breakpoint on a specific thread and symbol name is done with the bm command:
~tid bm sqlmin!CQueryScan::GetRow
But you have to be aware here that you don’t have to supply the OS thread ID. The bm command expects the thread number, which is just a zero-based number. When you switch on the correct OS thread with ~~[132E]s, you will see the thread number in the left bottom part of WinDbg.
When WinDbg reports a thread number like 47, you can set a breakpoint with the following command at the functionsqlmin!CQueryScan::GetRow on the correct thread:
~47 bm sqlmin!CQueryScan::GetRow
After setting the breakpoint, you can continue the execution of sqlservr.exe by using the F5 key. And after a few seconds (depending on the specified delay at the WAITFOR statement) WinDbg should break the execution at the specific breakpoint:
And now the real fun begins: you can explore the current call-stack with the k command, you can single-step through the assembly code, seeing how other functions are called. Your choices are endless, and only limited by your imagination.
Summary
I hope that with today’s blog posting I haven given you a more detailed look into how you can successfully set your first break point within sqlservr.exe to debug a specific query. Over the next weeks and months I’m trying to blog more details on how you can troubleshoot SQL Server with WinDbg. Stay tuned for more fun with WinDbg!
Thanks for reading
-Klaus
Debugging a SQL Server query with WinDbg的更多相关文章
- sql server query to get the list of column name in a table
--SQL Server 2005, 2008 or 2012: SELECT * FROM information_schema.tables --SQL Server 2000: SELECT * ...
- Microsoft SQL Server Query Processor Internals and Architecture
https://msdn.microsoft.com/en-us/library/aa226174(v=sql.70).aspx
- SQL Server Debugging with WinDbg – an Introduction
Klaus Aschenbrenner Klaus Aschenbrenner provides independent SQL Server Consulting Services across E ...
- Server-side Query interception with MS SQL Server
up vote15down votefavorite 5 I'm researching into intercepting queries that arrive at the SQL Serv ...
- SQL Server 2016新特性:Query Store
使用Query Store监控性能 SQL Server Query Store特性可以让你看到查询计划选择和性能.简化了性能调优,可以快速的发现因为查询计划的选择导致的性能的差别.Query Sto ...
- 非常全面的SQL Server巡检脚本来自sqlskills团队的Glenn Berry 大牛
非常全面的SQL Server巡检脚本来自sqlskills团队的Glenn Berry 大牛 Glenn Berry 大牛会对这个脚本持续更新 -- SQL Server 2012 Diagnost ...
- SQL Server 连接问题圣经-命名管道
SQL Server 连接问题圣经-命名管道 (1) APGC DSD Team 12 Jan 2011 1:24 AM 3 一.前言 在使用SQL Server 的过程中,用户遇到的最多的莫过于连接 ...
- SQL Server 优化器+SQL 基础
http://www.cnblogs.com/shanksgao/tag/%E4%BC%98%E5%8C%96%E5%99%A8/ http://www.cnblogs.com/double-K/ca ...
- SQL Server 连接问题-TCP/IP
原文:SQL Server 连接问题-TCP/IP 出自:http://blogs.msdn.com/b/apgcdsd/archive/2012/02/24/ms-sql-server-tcp-ip ...
随机推荐
- NMF分解(二)
应用: 一.图像分析 NMF最成功的一类应用是在图像的分析和处理领域.图像本身包含大量的数据,计算机一般将图像的信息按照矩阵的形式进行存放,针对图像的识别.分析和处理也是在矩阵的基础上进行的.这些特点 ...
- easyui-combogrid必填为空时无法通过表单验证的问题
在使用easyui-combogrid时,由于html解析出的格式是如下三层: <td> <input id="txcombo" class="easy ...
- python 二(续)——面向对象编程进阶
1.类的成员 2.类成员修饰符 3.类的特殊成员 在python第二课——面向对象初级,文章中介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一 ...
- 【LoadRunner】对摘要认证的处理
近期项目中,进行http协议的接口性能测试过程中,需要进行登录接口的摘要认证,分享一下测试经验. 测试准备 测试工具:LoadRunner11 测试类型:接口测试--某系统登录接口 步骤 根据系统接口 ...
- Android onConfigurationChanged用法(规避横竖屏切换导致的重新调用onCreate方法)
onConfigurationChanged的目的是为了规避横竖屏切换干掉activity而重新调用onCreate方法的问题:有的时候,我们希望重新进入OnCreate生命周期,此时可以调用onSa ...
- Wordpress 数据库查询错误 Call to a member function get_results() on null
在插件中的一个文件使用如下代码,无法查询 <body> <?php global $wpdb; $sql = ""; $sql = "SELECT * ...
- 模板与c++11--右值引用
函数参数传递 struct huge_data{ char *content; unsigned sz; huge_data():content(),sz(){ cout<<this< ...
- UVALive 5983 MAGRID DP
题意:在一个n*m的网格上,从(0,0)走到(n-1,m-1),每次只能向右或者向下走一格.一个人最初有一个生命值x,走到每一个格生命值会 变为x + s[i][j],(s[i][j]可为负,0,正) ...
- 【bzoj2048】[2009国家集训队]书堆 数论
题目描述 输入 第一行正整数 N M 输出 一行(有换行符),L,表示水平延伸最远的整数距离 (不大于答案的最大整数) 样例 #1 Input: 1 100 Output: 49 #2 Input: ...
- 【POJ2774】Long Long Message (SA)
最长公共子串...两个字符串连在一起,中间放一个特殊字符隔开.求出height之后,枚举height,看两个后缀是不是分布于两段字符串..如果是,这个值就可以作为答案.取最大值即可. ; var c, ...