我在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 (
?,?,?
);
困扰我的是Key lock资源框下的Index名称。
我在MA4TB_MT_LOG_MSG表下没有名为“1”的索引。
MSG_ID是MA4TB_MT_LOG_MSG的主键,DIST_DATE,DIST_CODE没有索引。
对此僵局情况的任何形式的建议都将不胜感激。
提前致谢,
答案 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
好的,没有索引的表有什么作用?这些表称为堆。他们在零位置有自己的索引,指向第一个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
简而言之,我们可以看到在零位置使用索引定义的堆。
那么什么是死锁,请求模式U是什么意思?
死锁是指两个进程同时获取资源但不以相同顺序获取资源的情况。简而言之,这两个过程都无法进行。引擎以最少的回滚时间选择会话并终止进程。
http://technet.microsoft.com/en-us/library/ms178104(v=sql.105).aspx
一张图片胜过千言万语!事务1抓取资源1.事务2抓取资源2.当他们尝试抓取彼此资源时,会创建死锁。
那么密钥锁和用户模式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事件探查器会生成比该图表/鼠标悬停中显示的信息更多的信息,并且该信息可能会或可能不会对您的问题有所了解。试试这个:
答案 2 :(得分:0)
Lock图表似乎显示整个表都被锁定。
从根本上说,我建议你查看你写的MERGE语句。确保您有适当的过滤条件。尝试使用适当的索引,以便更快地访问数据并减少锁定持续时间。只有当它们应该存在时才执行事务。了解哪个进程在MA4TB_MT_LOG_MS之上创建死锁场景,然后尝试解决该段代码。增加锁定选择性(即行\页锁定而不是表锁定)和持续时间。
你要看很多东西!
答案 3 :(得分:0)
我认为“索引名称:1”指的是聚集索引的对象ID