死锁图显示未知的索引名称

时间:2013-08-23 02:11:41

标签: sql sql-server jdbc deadlock

我在SQL Server 2012中遇到了死锁情况。

运行SQL Server Profiler后,我得到了一个死锁图,如下所示:

Deadlock graph

当鼠标移到进程(椭圆形)上时,两个进程都显示相同的PrepareStatement查询(我正在使用JDBC)。

我正在使用的查询如下:

MERGE INTO MA4TB_MT_LOG_MSG  USING (VALUES (1)) AS S(Num) ON ( MSG_ID = ? )
            WHEN MATCHED THEN
                UPDATE SET 
                    DIST_DATE   = ?,
                    DIST_CODE   = ?
            WHEN NOT MATCHED THEN
                INSERT (
                    MSG_ID, DIST_DATE, DIST_CODE
                ) VALUES (
                    ?,?,?
                );

困扰我的是Key lock资源框下的Index名称。

我在MA4TB_MT_LOG_MSG表下没有名为“1”的索引。

MSG_ID是MA4TB_MT_LOG_MSG的主键,DIST_DATE,DIST_CODE没有索引。

对此僵局情况的任何形式的建议都将不胜感激。

提前致谢,

4 个答案:

答案 0 :(得分:4)

让我们开始回答你的第一个问题。我没有索引id = 1。

是的,你做!!

让我们来看看SQL Server 2014 CTP2上的Adventure Works 2012数据库。这是我的笔记本电脑规格。

有一个表名[AWBuildVersion]。它有一个像表一样的聚簇索引。在索引下,我们可以看到PK正在出现。如果我们得到表的对象id(sys.objects)并查找索引的条目(sys.indexes),我们可以看到索引位于第1位。

简而言之,默认情况下,主键是聚簇索引。

http://technet.microsoft.com/en-us/library/ms177443(v=sql.105).aspx

enter image description here

好的,没有索引的表有什么作用?这些表称为堆。他们在零位置有自己的索引,指向第一个IAM页面。

http://technet.microsoft.com/en-us/library/ms188270(v=sql.105).aspx

下面的代码创建了一个名为[crafty]的模式,并使用SELECT INTO将[AWBuildVersion]表复制到新模式。 SELECT INTO的优点是没有索引。

use AdventureWorks2012
go

create schema [crafty] authorization [dbo];
go

select * into crafty.awbuildversion from dbo.awbuildversion
go

简而言之,我们可以看到在零位置使用索引定义的堆。

enter image description here

那么什么是死锁,请求模式U是什么意思?

死锁是指两个进程同时获取资源但不以相同顺序获取资源的情况。简而言之,这两个过程都无法进行。引擎以最少的回滚时间选择会话并终止进程。

http://technet.microsoft.com/en-us/library/ms178104(v=sql.105).aspx

一张图片胜过千言万语!事务1抓取资源1.事务2抓取资源2.当他们尝试抓取彼此资源时,会创建死锁。

enter image description here

那么密钥锁和用户模式U是什么意思?

要更新表格,您需要更新数据/索引页面。但是数据页实际上是表中的索引页(聚簇索引)。 SQL引擎取出(U)PDATE锁。在实际更新期间,此锁将升级为独占锁(X)。

当两个进程请求独占锁定时,可能存在死锁。

要完成此主题,可以在不阻塞的情况下执行共享锁(SELECT)(同时)通常,当Engines死锁进程线程检测到循环图时,进程从阻塞开始然后变为死锁。

默认隔离级别为Read Uncommitted。

http://technet.microsoft.com/en-us/library/ms175519(v=sql.105).aspx

此时,您遇到了僵局。

你从哪里开始?

1 - 可能有多个会话(SPID)运行相同的代码。为什么?你可以改变这个,这样一次只有一个进程运行代码吗?

2 - 获取JDBC生成的实际TSQL。这可以通过SQL分析器和/或查看您的DMV来完成。

merge语句同时执行UPDATE和/或INSERT。因此复合操作。

3 - 您可以将隔离级别更改为可序列化吗? http://technet.microsoft.com/en-us/library/ms173763.aspx

这将添加更多锁,并可能将您的死锁问题更改为超时问题。请参阅Kalen Daleny关于如何设置LOCK_TIMEOUT的文章。您将不得不调整代码以再次重试操作,并在两者之间有一些延迟。

http://sqlmag.com/sql-server/inside-sql-server-controlling-locking

我希望这些信息可以帮到你。

如果您需要更多帮助,请发布您的TSQL。

答案 1 :(得分:1)

SQL事件探查器会生成比该图表/鼠标悬停中显示的信息更多的信息,并且该信息可能会或可能不会对您的问题有所了解。试试这个:

  • 在Profiler中选择导致显示图表的行
  • 执行“复制”(ctrL + C或菜单选项)
  • 将其粘贴到文本编辑器(例如SSMS查询窗口)
  • 您想要的是Profiler“文本”列的XML内容 - 删除其他所有内容
  • 在XML编辑器中打开这个XML(无论你有什么让它变得清晰,我使用MIcrosoft的XML Notepad)
  • 向下钻取。它需要一点,但一旦你得到布局(层次结构,标签名称等)的东西应该是明确的事情

答案 2 :(得分:0)

Lock图表似乎显示整个表都被锁定。

从根本上说,我建议你查看你写的MERGE语句。确保您有适当的过滤条件。尝试使用适当的索引,以便更快地访问数据并减少锁定持续时间。只有当它们应该存在时才执行事务。了解哪个进程在MA4TB_MT_LOG_MS之上创建死锁场景,然后尝试解决该段代码。增加锁定选择性(即行\页锁定而不是表锁定)和持续时间。

你要看很多东西!

答案 3 :(得分:0)

我认为“索引名称:1”指的是聚集索引的对象ID