Debugging a SQL Server query with WinDbg

Debugging a SQL Server query with WinDbg

May 13, 2014 · Klaus Aschenbrenner · 5 Comments

(Be sure to checkout the FREE SQLpassion Performance Tuning Training Plan - you get a weekly email packed with all the essential knowledge you need to know about performance tuning on SQL Server.)

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:

  1. Retrieve in a different session the OS thread ID for your (waiting) query from sys.dm_os_threads
  2. Convert the OS thread ID to a hex value
  3. Break sqlservr.exe with CTRL + BREAK
  4. Switch to the correct OS thread with the command ~~[tid]s
  5. Set a breakpoint on the specific thread
  6. Continue the execution of sqlservr.exe
  7. 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

时间: 2024-10-24 22:03:26

Debugging a SQL Server query with WinDbg的相关文章

SQL Server Query Execution Plan Analysis

SQL Server Query Execution Plan Analysis Source:http://www.sql-server-performance.com/tips/query_execution_plan_analysis_p1.aspx 当需要分析某个查询的效能时,最好的方式之一查看这个查询的执行计划.执行计划描述SQL Server查询优化器如何实际运行(或者将会如何运行)一个特定的查询. 查看查询的执行计划有几种不同的方式.它们包括: SQL Server查询分析器里有一

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 * FROM sysobjects WHERE xtype='U' SELECT * FROM sysobjects WHERE xtype='U' SELECT TABLE_NAME FROM geovidnu.INFORMATION_SCHEMA.Tables SELECT sobjects.na

SQL Server Debugging with WinDbg – an Introduction

Klaus Aschenbrenner Klaus Aschenbrenner provides independent SQL Server Consulting Services across Europe and the US. Klaus works with the .NET Framework and especially with the SQL Server 2005/2008 from the very beginnings. In the years 2004 - 2005

SQL optimizer -Query Optimizer Deep Dive

refer: http://sqlblog.com/blogs/paul_white/archive/2012/04/28/query-optimizer-deep-dive-part-1.aspx    SQL是一种结构化查询语言规范,它从逻辑是哪个描述了用户需要的结果,而SQL服务器将这个逻辑需求描述转成能执行的物理执行计划,从而把结果返回给用户.将逻辑需求转换成一个更有效的物理执行计划的过程,就是优化的过程. 执行SQL的过程: Input Tree We start by looking

SQL Server 优化器+SQL 基础

http://www.cnblogs.com/shanksgao/tag/%E4%BC%98%E5%8C%96%E5%99%A8/ http://www.cnblogs.com/double-K/category/759248.html http://www.cnblogs.com/zhijianliutang/category/636063.html http://www.cnblogs.com/lonelyxmas/p/4685085.html       stack生成          

SQL Server中迁移数据的几种方法

1.通过工具"DTS"的设计器进行导入或者导出 DTS的设计器功能强大,支持多任务,也是可视化界面,容易操作,但知道的人一般不 多,如果只是进行SQL Server数据库中部分表的移动,用这种方法最好,当然,也可以进行全部表的移动.在SQL Server Enterprise Manager中,展开服务器左边的+,选择数据库,右击,选择All tasks/Import Data...(或All tasks/Export Data...),进入向导模式,按提示一步一步走就行了,里面分得很

教程:SQL Server Management Studio

此工具由 Microsoft Visual Studio, Management Studio 内部承载,它提供了用于数据库管理的图形工具和功能丰富的开发环境.通过 Management Studio,您可以在同一个工具中访问和管理数据库引擎.Analysis Manager 和 SQL 查询分析器,并且能够编写 Transact-SQL.MDX.XMLA 和 XML 语句.  学习内容 熟悉 Management Studio 的最好方式是进行实践演练.本教程将讲述如何管理 Managemen

sql server internal book

Frequently Bought Together + + Total price: $131.71 Add all three to CartAdd all three to List Buy the selected items together This item:Pro SQL Server Internals by Dmitri Korotkevitch Paperback $53.69 Microsoft SQL Server 2014 Query Tuning & Optimiz

SQL Server 连接问题-TCP/IP

原文:SQL Server 连接问题-TCP/IP 出自:http://blogs.msdn.com/b/apgcdsd/archive/2012/02/24/ms-sql-server-tcp-ip.aspx TCP/IP的基本工作原理这里就不浪费口水了.现在这网络年代,谁不知道TCP/IP啊.不要跟我抬杠说你偏就没听说过TCP/IP阿,真是这样那你得自己去补补课了. TCP/IP协议有两个基本的东西,一个是IP地址, 另一个是端口号. 在SQL Server 上使用TCP/IP协议是非常简单