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

wns*_*349 5 sql sql-server deadlock jdbc

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

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

死锁图

将鼠标移到进程(椭圆形)上时,两个进程都显示相同的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 (
                    ?,?,?
                );
Run Code Online (Sandbox Code Playgroud)

困扰我的是Key lock资源框下的Index name.

我在MA4TB_MT_LOG_MSG表下没有名为"1"的索引.

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

关于这种僵局情况的任何形式的建议将不胜感激.

提前致谢,

CRA*_*DBA 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

在此输入图像描述

好吧,那么没有索引的表有什么呢?这些表称为堆。他们确实在位置 0 处有自己的索引,指向第一个 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
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

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

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

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

一张图片胜过千言万语!事务 1 获取资源 1。事务 2 获取资源 2。当它们尝试获取彼此的资源时,就会产生死锁。

在此输入图像描述

那么按键锁和用户模式U是什么意思呢?

要更新表,您需要更新数据/索引页。但数据页实际上是表中的索引页(聚集索引)。SQL 引擎取出 (U)PDATE 锁。在实际更新期间,该锁将升级为排它锁(X)。

当两个进程请求独占锁时,就有可能出现死锁。

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

默认隔离级别是未提交读。

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。