问题描述
您能否帮助我们理解为什么在更新引用分区表上的分区键列时存在死锁?
(基本上,想知道为什么下面脚本的第三次更新会阻塞,
a)我们不更新被另一个会话阻止的行,并且
b)我们甚至不更新主键列(因为这可能导致子表上的全表锁定,原因是外键没有索引)
)
(基本上,想知道为什么下面脚本的第三次更新会阻塞,
a)我们不更新被另一个会话阻止的行,并且
b)我们甚至不更新主键列(因为这可能导致子表上的全表锁定,原因是外键没有索引)
)
drop table child_tab purge; drop table parent_tab purge; create table parent_tab ( col1 number, col2 number, constraint parent_tab_pk primary key(col1) ) enable row movement partition by list(col2) ( partition p1 values (1), partition p2 values (2), partition p3 values (3), partition p4 values (4), partition p5 values (default) ); create table child_tab ( col1 number not null, col2 number, constraint child_tab_fk foreign key(col1) references parent_tab ) enable row movement partition by reference(child_tab_fk); insert into parent_tab(col1,col2) select level,level from dual connect by level <=5; insert into child_tab(col1,col2) select level,level from dual connect by level <=5; commit; --session 1 update parent_tab set col2 = col2 + 1 where col1 = 1; --session 2 update child_tab set col2 = col2 + 1 where col1 = 2; --session 1 <<= this will be blocked now. update parent_tab set col2 = col2 + 1 where col1 = 2; -- session 2 <<= this will produce ORA-00060: deadlock on Session-1 update child_tab set col2 = col2 + 1 where col1 = 1;
专家解答
更新父表中的分区键时, Oracle还必须更新子表中的相应行。这使它能够将子行移动到新分区。
让我们看一下您的示例:
1 :在父项和子项中移动行1 => P2。将此行同时锁定。
2 :更新子级中的行2。在子代中锁定此行。
3 :在父项和子项中移动行2 => P3。锁定父行。尝试锁定子级中的第2行。这被步骤2阻止。
4 :更新子级中的行1。锁定此行的尝试被步骤1阻止。
因此,会话1正在等待子行2上的锁。会话2正在等待行1上的子锁。死锁!
实际上是孩子的更新导致了这一点。我在更新父级时收到死锁:
当您查看死锁跟踪时,您将看到如下所示:
这表明它实际上是对子项的更新导致了异常。
让我们看一下您的示例:
1 :在父项和子项中移动行1 => P2。将此行同时锁定。
2 :更新子级中的行2。在子代中锁定此行。
3 :在父项和子项中移动行2 => P3。锁定父行。尝试锁定子级中的第2行。这被步骤2阻止。
4 :更新子级中的行1。锁定此行的尝试被步骤1阻止。
因此,会话1正在等待子行2上的锁。会话2正在等待行1上的子锁。死锁!
实际上是孩子的更新导致了这一点。我在更新父级时收到死锁:
CHRIS> update parent_tab
2 set col2 = col2 + 1
3 where col1 = 2;
update parent_tab
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-00060: deadlock detected while waiting for resource当您查看死锁跟踪时,您将看到如下所示:
update
/*+ opt_param('_and_pruning_enabled', 'false') */
"CHRIS"."CHILD_TAB" partition ( dataobj_to_partition("CHRIS"."PARENT_TAB" , :1))
move to partition (dataobj_to_partition( "CHRIS"."PARENT_TAB" , :1))
set "COL1" = "COL1"
where "COL1" = :1这表明它实际上是对子项的更新导致了异常。
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




