Oracle对象的死锁

来源:互联网 发布:js获取设备ip 编辑:程序博客网 时间:2024/05/18 02:36

oracle 死锁介绍

博客分类: Oracle
Oracle编程SQL
如果你有两个会话,每个会话都持有另一个会话想要的资源,此时就会出现死锁(deadlock)。例如,如果我的数据库中有两个表A和B,每个表中都只有一行,就可以很容易地展示什么是死锁。我要做的只是打开两个会话(例如,两个SQL*Plus会话)。在会话A中更新表A,并在会话B中更新表B。现在,如果我想在会话B中更新表A,就会阻塞。会话A已经锁定了这一行。这不是死锁;只是阻塞而已。我还没有遇到过死锁,因为会话A还有机会提交或回滚,这样会话B就能继续。如果我再回到会话A,试图更新表B,这就会导致一个死锁。要在这两个会话中选择一个作为“牺牲品”,让它的语句回滚。
想要更新表B的会话A还阻塞着,Oracle不会回滚整个事务。只会回滚与死锁有关的某条语句。会话B仍然锁定着表B中的行,而会话A还在耐心地等待这一行可用。收到死锁消息后,会话B必须决定将表B上未执行的工作提交还是回滚,或者继续走另一条路,以后再提交。一旦这个会话执行提交或回滚,另一个阻塞的会话就会继续,好像什么也没有发生过一样。
显然,Oracle认为这些应用死锁是应用自己导致的错误,而且在大多数情况下,Oracle的这种看法都是正确的。不同于许多其他的RDBMS,Oracle中极少出现死锁,甚至可以认为几乎不存在。通常情况下,必须人为地提供条件才会产生死锁。
根据我的经验,导致死锁的头号原因是外键未加索引(第二号原因是表上的位图索引遭到并发更新,这个内容将在第11章讨论)。在以下两种情况下,Oracle在修改父表后会对子表加一个全表锁:
1. 如果更新了父表的主键(倘若遵循关系数据库的原则,即主键应当是不可变的,这种情况就很少见),由于外键上没有索引,所以子表会被锁住。
2. 如果删除了父表中的一行,整个子表也会被锁住(由于外键上没有索引)。
总之,就是更新或者删除父表的主键,都会导致对其子表加一个全表锁。
除了全表锁外,在以下情况下,未加索引的外键也可能带来问题:
1. 如果有ON DELETE CASCADE,而且没有对子表加索引:例如,EMP是DEPT的子表,DELETE DEPTNO = 10应该CASCADE(级联)至EMP[4]。如果EMP中的DEPTNO没有索引,那么删除DEPT表中的每一行时都会对EMP做一个全表扫描。这个全表扫描可能是不必要的,而且如果从父表删除多行,父表中每删除一行就要扫描一次子表。
2. 从父表查询子表:再次考虑EMP/DEPT例子。利用DEPTNO查询EMP表是相当常见的。如果频繁地运行以下查询(例如,生成一个报告),你会发现没有索引会使查询速度变慢:
. select * from dept, emp
. where emp.deptno = dept.deptno and dept.deptno = :X;
那么,什么时候不需要对外键加索引呢?答案是,一般来说,当满足以下条件时不需要加索引:
1. 没有从父表删除行。
2. 没有更新父表的惟一键/主键值(当心工具有时会无意地更新主键!)。
3. 没有从父表联结子表(如DEPT联结到EMP)。
如果满足上述全部3个条件,那你完全可以跳过索引,不需要对外键加索引。如果满足以上的某个条件,就要当心加索引的后果。这是一种少有的情况,即Oracle“过分地锁定了”数据。
以下为我对oracle死锁的理解:有两个表A和B:A是父表,B是子表。如果没有在B表中的外键加上索引,那么A表在更新或者删除主键时,都会在表B上加一个全表锁。这是为什么呢?因为我们没有给外键加索引,在更新或者删除A表主键的时候,需要查看子表B中是否有对应的记录,以判断是否可以更新删除。那如何查找呢?当然只能在子表B中一条一条找了,因为我们没有加索引吗。既然要在子表B中一条一条地找,那就得把整个子表B都锁定了。由此就会导致以上一系列问题。

0 0