具有相同主键的行上的oracle数据库(由datapump导入)死锁(插入并选择以进行更新)

具有相同主键的行上的oracle数据库(由datapump导入)死锁(插入并选择以进行更新),oracle,deadlock,Oracle,Deadlock,这个问题只发生在数据库用户身上,它是由datapump导入的。原始数据库用户不存在此问题 我在oracle 11.2.0.3版本中遇到死锁,其中参与死锁的两个事务的当前SQL如下所示: SELECT /*AApaAA*/ objectid FROM T_DS_0 WHERE objectid = :1 FOR UPDATE insert /*AApaAA*/ into T_DS_0(OBJECTID) values (:1 ) ---------Blocker(s

这个问题只发生在数据库用户身上,它是由datapump导入的。原始数据库用户不存在此问题

我在oracle 11.2.0.3版本中遇到死锁,其中参与死锁的两个事务的当前SQL如下所示:

 SELECT /*AApaAA*/ objectid FROM T_DS_0 WHERE objectid = :1 FOR UPDATE

 insert /*AApaAA*/ into T_DS_0(OBJECTID) values (:1 )
            ---------Blocker(s)-------- ---------Waiter(s)---------
 Resource Name      process session holds waits  process session holds waits
 TX-000c000f-00000322    49 102     X                  46    587          X
 TX-00070011-00000da4    46 587     X                  49    102          S
TX1: 1.INSERT (objectid1) (fails and does not lock)
TX1: 2.SELECT (objectid1) (locks SDMBase)
TX2: 1.INSERT (objectid1) (fails but locks PK)
TX1: 3.INSERT (objectid1) (waits on PK)
TX2: 2.SELECT (objectid1) (waits on SDMBase)
两个绑定变量都是“AApaAA”,也是主键。它看起来像是单个资源上的死锁

有一些外键(在删除级联上)指向该主键,它们被索引

死锁图如下所示:

 SELECT /*AApaAA*/ objectid FROM T_DS_0 WHERE objectid = :1 FOR UPDATE

 insert /*AApaAA*/ into T_DS_0(OBJECTID) values (:1 )
            ---------Blocker(s)-------- ---------Waiter(s)---------
 Resource Name      process session holds waits  process session holds waits
 TX-000c000f-00000322    49 102     X                  46    587          X
 TX-00070011-00000da4    46 587     X                  49    102          S
TX1: 1.INSERT (objectid1) (fails and does not lock)
TX1: 2.SELECT (objectid1) (locks SDMBase)
TX2: 1.INSERT (objectid1) (fails but locks PK)
TX1: 3.INSERT (objectid1) (waits on PK)
TX2: 2.SELECT (objectid1) (waits on SDMBase)
我不清楚死锁是如何在单个资源上发生的。的确,insert并没有锁定行,而是锁定可能是另一种资源的约束,因此,如果第一个事务执行锁定约束,然后锁定行,而另一个事务的顺序相反,理论上可能会出现死锁,但我看不出这是如何发生的。从理论上讲,子表锁定是可能的(insert导致子表上出现SX),但select for update不应触及子表

oracle的完整跟踪文件位于:

有没有人经历过类似的行为

附加信息:此问题仅在使用datapump复制db用户时发生。原始架构包含在主键创建期间创建的SYS索引。还有以主键列开头的其他索引。然后,Datapump不会在主键列上创建SYS索引,而是使用从主键列开始的索引

当我创建以下数据库对象时:

创建表tbl(objectid varchar2(30),一个整数,主键(objectid))

在tbl(objectid,a)上创建索引idx1

创建了1个表和2个索引。SYS索引(OBJECTID)和idx1(OBJECTID,A)。主键使用SYS索引

执行数据泵si后,在导入端仅创建1个表和1个索引,索引为idx1(OBJECTID,A),该索引用于主键

这发生在我的数据库模式和表SDMBase中。当我在不同的事务中使用INSERT INTO SDMBase的组合时,就会发生死锁。。。然后选择。。。从SDMBase。。。用于更新,其中我使用相同的OBJECTID。在这些事务中执行相同的代码,在1个事务中可以如下所示

1.INSERT (objectid1)
2.SELECT FOR UPDATE (objectid1)
3.INSERT (objectid1)
4.SELECT FOR UPDATE (objectid1)

死锁情况发生在2号线上。和第三行。在我的用例中,当这些事务运行时,ObjectD1所在的行已经在数据库中,但还不必提交

所以我想

step 1. should wait until objectid1 is commited and then fail and lock nothing
step 2. should lock objectid1 or wait if another transaction already locked it
step 3. should fail immediately and lock nothing

显然,步骤1即使失败,也会在PK上保持一段时间的锁定,但只有在数据库被数据泵复制的情况下

这些死锁是罕见的,不可手动复制,我认为锁不是在整个事务中保持的,而是在很短的时间内保持的

因此,可以如下所示:

 SELECT /*AApaAA*/ objectid FROM T_DS_0 WHERE objectid = :1 FOR UPDATE

 insert /*AApaAA*/ into T_DS_0(OBJECTID) values (:1 )
            ---------Blocker(s)-------- ---------Waiter(s)---------
 Resource Name      process session holds waits  process session holds waits
 TX-000c000f-00000322    49 102     X                  46    587          X
 TX-00070011-00000da4    46 587     X                  49    102          S
TX1: 1.INSERT (objectid1) (fails and does not lock)
TX1: 2.SELECT (objectid1) (locks SDMBase)
TX2: 1.INSERT (objectid1) (fails but locks PK)
TX1: 3.INSERT (objectid1) (waits on PK)
TX2: 2.SELECT (objectid1) (waits on SDMBase)
即使我在导入的门户中创建索引作为SDMBase(OBJECTID)并让主键使用它,即使我重新创建另一个索引(OBJECTID…),它仍然会死锁。因此,我认为PK约束检查存在一些问题

解决这个问题的方法是创建SDMBase(OBJECTID),让主键使用它,然后再次执行数据泵。导入必须分两步执行,第一步排除索引,第二步仅导入索引

  • 排除=索引/索引,统计信息
  • include=索引/索引内容=仅元数据

  • 11.2.0.3和12.2.0.1中都会出现此问题

    为什么选择更新表中尚不存在的行AApaAA?它是由下一个insert命令插入的。或者可能我遗漏了什么?第一个事务插入该行并用它们自己的事务启动更多线程,但它们可以在提交原始行时首先启动。因此,在每个发送的开始,嵌套事务中都会插入同一行。如果行是由原始TX提交的,则此命令将失败,这是预期的行为。如果已回滚,则此插入将通过,这是一个错误。如果原始发送尚未提交,它将等待。一旦它正确通过(由于UQ冲突而失败),我们将锁定该行,以便其他人无法处理它。这是更新的选择。您能检查哪个对象导致死锁吗?我想您可以这样找到它:
    select*from dba\u objects,其中object\u id=85986。可能死锁发生在您没有考虑的对象上-可能是其他相关的表、位图索引等。不幸的是,这显示了T_DS_0。另一边会更有趣,但它没有“行”。我想会有主键索引。所以死锁可能会发生,因为我们有两个资源。我只是不知道命令的顺序。seq 1:insert,sfu(选择进行更新),seq 2:sfu,insert无法工作,因为如果该行存在,insert将失败且不应锁定,如果该行不存在,sfu将不锁定。我没有适当的删除。为什么选择更新表中尚不存在的行AAAAA?它是由下一个insert命令插入的。或者可能我遗漏了什么?第一个事务插入该行并用它们自己的事务启动更多线程,但它们可以在提交原始行时首先启动。因此,在每个发送的开始,嵌套事务中都会插入同一行。如果行是由原始TX提交的,则此命令将失败,这是预期的行为。如果已回滚,则此插入将通过,这是一个错误。如果原始发送尚未提交,它将等待。一旦它正确通过(由于UQ冲突而失败),我们将锁定该行,以便其他人无法处理它。这是更新的选择。你能检查一下吗