首页 > 代码库 > 父表、子表 主外键关系

父表、子表 主外键关系

 

 

ORACLE官方文档介绍:

Concurrency Control, Indexes, and Foreign Keys

You almost always index foreign keys. The only exception is when the matching unique or primary key is never updated or deleted.(你总是需要对 外键添加索引! 唯一的例外就是:匹配的主键列 或是 唯一列 从不进行更新操作或者 删除操作)

Oracle maximizes the concurrency control of parent keys in relation to dependent foreign key values. You can control what concurrency mechanisms are used to maintain these relationships, and, depending on the situation, this can be highly beneficial. The following sections explain the possible situations and give recommendations for each.

No Index on the Foreign Key

Figure 21-8 illustrates the locking mechanisms used by Oracle when no index is defined on the foreign key and when rows are being updated or deleted in the parent table. Inserts into the parent table do not require any locks on the child table.

(当子表外键上没有索引时,对父表做 删除、更新操作时,会锁定子表。插入操作不需要 锁定子表)

Unindexed foreign keys cause DML on the primary key to get a share row exclusive table lock (also sometimes called a share-subexclusive table lock, SSX) on the foreign key table. This prevents DML on the table by other transactions. The SSX lock is released immediately after it is obtained. If multiple primary keys are updated or deleted, the lock is obtained and released once for each row.

Note:

See Also:

"DML Locks"

Figure 21-8 Locking Mechanisms When No Index Is Defined on the Foreign Key

 

 

Description of "Figure 21-8 Locking Mechanisms When No Index Is Defined on the Foreign Key"

Index on the Foreign Key

Figure 21-9 illustrates the locking mechanisms used when an index is defined on the foreign key, and new rows are inserted, updated, or deleted in the child table.

Indexed foreign keys cause a row share table lock (also sometimes called a subshare table lock, SS). This prevents other transactions from exclusive locking the whole table, but it does not block DML on the parent or the child table.

This situation is preferable if there is any update or delete activity on the parent table while update activity is taking place on the child table. Inserts, updates, and deletes on the parent table do not require any locks on the child table, although updates and deletes will wait for row-level locks on the indexes of the child table to clear.

Figure 21-9 Locking Mechanisms When Index Is Defined on the Foreign Key


Description of "Figure 21-9 Locking Mechanisms When Index Is Defined on the Foreign Key"

If the child table specifies ON DELETE CASCADE, then deletes from the parent table can result in deletes from the child table. In this case, waiting and locking rules are the same as if you deleted yourself from the child table after performing the delete from the parent table.

 

 

 

 

 

 

 

 

 

 

 

 

 

子表的外键 字段没有 索引!!!

 

创建测试环境

TEST @ prod >create table father as select * from scott.dept;

 

Table created.

 

TEST @ prod >create table childen as select * from scott.emp;

 

Table created.

 

TEST @ prod >alter table father add constraint pk_deptno primary key (deptno);

 

Table altered.

 

TEST @ prod >alter table childen add constraint fk_deptno foreign key (deptno) references father(deptno);

 

Table altered.

 

此时子表外键 不加索引

 

 

 

查锁语句

创建脚本 chk_lock.sql,利用游标查询被锁定的对象lock的模式

[oracle@cuug ~]$ vi chk_lock.sql

declare

v1 lock_more%rowtype;

cursor c1 is select lk.sid,lk_obj.object_id,obj.object_name,DECODE(LK.LMODE,0,‘None‘,1,‘Null‘,2,‘Row-S (SS)‘,3,‘Row-X (SX)‘,4,‘Share‘,5,‘S/Row-X (SSX)‘,6,‘Exclusive‘) lmode

from v$locked_object lk_obj,dba_objects obj,v$lock lk

where lk.sid=lk_obj.session_id and lk_obj.object_id=obj.object_id and lk.sid=154;

begin

open c1;

loop

fetch c1 into v1;

exit when c1%notfound;

insert into lock_more values(v1.locker_sid,v1.locked_objno,v1.locked_obj,v1.lock_mode);

commit;

end loop;

end;

/

 

创建表lock_more 存放 脚本chk_lock.sql 查询出的结果

SYS @ prod >create table lock_more (locker_sid number,locked_objno number,locked_obj varchar(10),lock_mode varchar(20));

 

Table created.

 

父表插入数据,数据库中 锁的情况

SYS @ prod >insert into father values(50,‘beijing‘,‘china‘);

 

1 row created.

 

SYS @ prod >@chk_lock.sql;

 

PL/SQL procedure successfully completed.

 

SYS @ prod >select * from lock_more;

 

LOCKER_SID LOCKED_OBJNO LOCKED_OBJ LOCK_MODE

---------- ------------ ---------- --------------------

       154        52514 FATHER     Exclusive

       154        52515 CHILDEN    Row-X (SX)

       154        52515 CHILDEN    Row-S (SS)

       154        52515 CHILDEN    Exclusive

       154        52514 FATHER     Row-X (SX)

   154        52514 FATHER     Row-S (SS)

 

结论:INSERT操作会同时锁定 父表、子表

 

子表插入数据,观察该对象是否被锁

SYS @ prod >insert into childen values(1111,‘test‘,‘test‘,8888,‘28-SEP-81‘,8,0,50);

 

1 row created.

 

SYS @ prod >@chk_lock.sql;

 

PL/SQL procedure successfully completed.

 

SYS @ prod >select * from lock_more;

 

LOCKER_SID LOCKED_OBJNO LOCKED_OBJ LOCK_MODE

---------- ------------ ---------- --------------------

       154        52514 FATHER     Exclusive

       154        52515 CHILDEN    Row-S (SS)

       154        52515 CHILDEN    Row-X (SX)

       154        52515 CHILDEN    Exclusive

       154        52514 FATHER     Row-S (SS)

       154        52514 FATHER     Row-X (SX)

 

结论:子表插入数据,会同时锁定 父表、子表

 

 

父表更新数据,观察该对象 是否被锁

[oracle@cuug ~]$ vi ct_lock.sql

declare

begin

for i in 4..10000 loop

update father set deptno=deptno*1 ;

end loop;

end;

 /

 

SYS @ prod >@ct_lock.sql;

 

PL/SQL procedure successfully completed.

 

SYS @ prod >@chk_lock.sql;

 

PL/SQL procedure successfully completed.

SYS @ prod >select * from lock_more;

 

LOCKER_SID LOCKED_OBJNO LOCKED_OBJ LOCK_MODE

---------- ------------ ---------- --------------------

       154        52514 FATHER     Row-X (SX)

       154        52514 FATHER     Exclusive

 

结论:对父表做Update操作,只会锁定父表不会锁定子表

 

子表更新数据,观察该对象 是否被锁

[oracle@cuug ~]$ vi ct_lock.sql

declare

begin

for i in 4..10000 loop

update childen set deptno=deptno*1 ;

end loop;

end;

 /

 

SYS @ prod >@ct_lock.sql;

 

PL/SQL procedure successfully completed.

 

SYS @ prod >@chk_lock.sql;

 

PL/SQL procedure successfully completed.

 

LOCKER_SID LOCKED_OBJNO LOCKED_OBJ LOCK_MODE

---------- ------------ ---------- --------------------

       154        52514 FATHER     Row-S (SS)

       154        52514 FATHER     Row-X (SX)

       154        52514 FATHER     Exclusive

       154        52515 CHILDEN    Row-S (SS)

       154        52515 CHILDEN    Row-X (SX)

       154        52515 CHILDEN    Exclusive

 

结论:在子表执行 update操作,会同时锁定 父表、子表

 

 

 

 

 

父表删除数据,观察该对象 是否被锁

SYS @ prod >delete from father where deptno=50;

 

1 row deleted.

 

SYS @ prod >@chk_lock.sql;

 

PL/SQL procedure successfully completed.

 

 

SYS @ prod >select * from lock_more;

 

LOCKER_SID LOCKED_OBJNO LOCKED_OBJ LOCK_MODE

---------- ------------ ---------- --------------------

       154        52514 FATHER     Row-X (SX)

       154        52514 FATHER     Exclusive

 

结论:在父表执行Delete操作不提交,只会锁定父表不会锁定子表

 

 

 

子表删除数据,观察对象是否被锁

SYS @ prod >delete from childen where deptno=50;

 

1 row deleted.

 

SYS @ prod >@chk_lock.sql;

 

PL/SQL procedure successfully completed.

 

SYS @ prod >select * from lock_more;

 

LOCKER_SID LOCKED_OBJNO LOCKED_OBJ LOCK_MODE

---------- ------------ ---------- --------------------

       154        52514 FATHER     Exclusive

       154        52515 CHILDEN    Row-S (SS)

       154        52515 CHILDEN    Row-X (SX)

       154        52515 CHILDEN    Exclusive

       154        52514 FATHER     Row-S (SS)

       154        52514 FATHER     Row-X (SX)

 

结论:在子表执行delete操作不提交,会同时锁定 父表、子表

 

子表的外键字段添加索引

SYS @ prod >create index ind_deptno on childen(deptno);

 

Index created.

 

SYS @ prod >analyze table childen compute statistics;

 

Table analyzed.

 

http://www.itpub.net/forum.php?mod=viewthread&tid=1804873&page=1#pid21588601

 

http://www.itpub.net/forum.php?mod=viewthread&tid=1804873

 

http://www.itpub.net/forum.php?mod=viewthread&tid=1850815&page=2#pid22202575

 

http://www.itpub.net/forum.php?mod=viewthread&tid=1445975

 

 

 

 

 

 

 

父表插入数据,观察该对象 是否被锁

SYS @ prod >insert into father values(50,‘beijing‘,‘china‘);

 

1 row created.

 

SYS @ prod >@chk_lock.sql;

 

PL/SQL procedure successfully completed.

 

SYS @ prod >select * from lock_more;

 

LOCKER_SID LOCKED_OBJNO LOCKED_OBJ LOCK_MODE

---------- ------------ ---------- --------------------

       154        52514 FATHER     Row-X (SX)

       154        52514 FATHER     Row-S (SS)

       154        52514 FATHER     Exclusive

       154        52515 CHILDEN    Row-X (SX)

       154        52515 CHILDEN    Row-S (SS)

   154        52515 CHILDEN    Exclusive

 

结论:INSERT操作会同时锁定 父表、子表

 

子表插入数据,观察该对象是否被锁

SYS @ prod >insert into childen values(1111,‘test‘,‘test‘,8888,‘28-SEP-81‘,8,0,50);

 

1 row created.

 

SYS @ prod >@chk_lock.sql;

 

PL/SQL procedure successfully completed.

 

 

SYS @ prod >select * from lock_more;

 

LOCKER_SID LOCKED_OBJNO LOCKED_OBJ LOCK_MODE

---------- ------------ ---------- --------------------

       154        52514 FATHER     Exclusive

       154        52515 CHILDEN    Row-S (SS)

       154        52515 CHILDEN    Row-X (SX)

       154        52515 CHILDEN    Exclusive

       154        52514 FATHER     Row-S (SS)

       154        52514 FATHER     Row-X (SX)

 

结论:子表插入数据,会同时锁定 父表、子表

 

 

父表更新数据,观察该对象 是否被锁

[oracle@cuug ~]$ vi ct_lock.sql

declare

begin

for i in 4..10000 loop

update father set deptno=deptno*1 ;

end loop;

end;

 /

.

SYS @ prod >@ct_lock.sql;

 

PL/SQL procedure successfully completed.

 

 

SYS @ prod >@chk_lock.sql;

 

PL/SQL procedure successfully completed.

 

SYS @ prod >select * from lock_more;

 

LOCKER_SID LOCKED_OBJNO LOCKED_OBJ LOCK_MODE

---------- ------------ ---------- --------------------

       154        52514 FATHER     Row-X (SX)

       154        52514 FATHER     Row-X (SX)

       154        52514 FATHER     Exclusive

       154        52515 CHILDEN    Row-X (SX)

       154        52515 CHILDEN    Row-X (SX)

       154        52515 CHILDEN    Exclusive

 

结论:Update操作不提交 ,会同时锁定父表、子表

 

 

子表更新数据,观察该对象 是否被锁

SYS @ prod >update childen set deptno=deptno*1 ;

 

14 rows updated.

 

SYS @ prod >@chk_lock.sql;

 

PL/SQL procedure successfully completed.

 

SYS @ prod >select * from lock_more;

 

LOCKER_SID LOCKED_OBJNO LOCKED_OBJ LOCK_MODE

---------- ------------ ---------- --------------------

       154        52514 FATHER     Exclusive

       154        52515 CHILDEN    Row-S (SS)

       154        52515 CHILDEN    Row-X (SX)

       154        52515 CHILDEN    Exclusive

       154        52514 FATHER     Row-S (SS)

       154        52514 FATHER     Row-X (SX)

 

结论:在子表执行 update操作,会同时锁定 父表、子表

 

父表删除数据,观察该对象 是否被锁

SYS @ prod >delete from father where deptno=50;

 

1 row deleted.

 

SYS @ prod >@chk_lock.sql;

 

PL/SQL procedure successfully completed.

 

SYS @ prod >select * from lock_more;

 

LOCKER_SID LOCKED_OBJNO LOCKED_OBJ LOCK_MODE

---------- ------------ ---------- --------------------

       154        52514 FATHER     Exclusive

       154        52515 CHILDEN    Row-X (SX)

       154        52515 CHILDEN    Row-S (SS)

       154        52515 CHILDEN    Exclusive

       154        52514 FATHER     Row-X (SX)

       154        52514 FATHER     Row-S (SS)

 

结论:父表删除数据 会同时锁定 父表、子表

 

 

子表删除数据,观察对象是否被锁

SYS @ prod >delete from childen where deptno=10;

 

3 rows deleted.

 

 

SYS @ prod >@chk_lock.sql;

 

PL/SQL procedure successfully completed.

 

 

SYS @ prod >select * from lock_more;

 

LOCKER_SID LOCKED_OBJNO LOCKED_OBJ LOCK_MODE

---------- ------------ ---------- --------------------

       154        52514 FATHER     Exclusive

       154        52515 CHILDEN    Row-S (SS)

       154        52514 FATHER     Row-S (SS)

       154        52514 FATHER     Row-X (SX)

       154        52515 CHILDEN    Row-X (SX)

       154        52515 CHILDEN    Exclusive

 

结论:子表删除数据同时 锁定 主表、子表

 

 

结论:

 

子表外键未创建索引

 

INSERT

UPDATE

DELETE

父表

锁父表、子表

锁父表

锁父表、锁子表

子表

锁父表、子表

锁父表、子表

锁父表、子表

 

 

子表外键创建索引

 

INSERT

UPDATE

DELETE

父表

锁父表、子表

锁父表、子表

锁父表、子表

子表

锁父表、子表

锁父表、子表

锁父表、子表

 

 

 

 

 

外键上无索引

         如果外键(foreign key)上没有定义索引,当父表(parent table)中的数据行被更新或删除时,Oracle 采用的锁机制(locking mechanism)如 图 21-8 所示。而向父表中插入数据时无需对子表(child table)加锁。

 

 

如果外键上没有定义索引,对父表的主键执行 DML 操作时必须获得子表上的共享行排他表级锁(share row exclusive table lock)(也称为 share-subexclusive table lock,SSX)。此锁能够阻止其他事务对子表执行 DML 操作。SSX 锁在获得后立即释放。如果父表中有多个主键值被更新或删除,对每行执行 DML 操作时都需要对子表进行一次加锁及解锁操作。
 

           如果外键上定义了索引,则对父表的主键执行 DML 操作时只需获得子表上的行共享表级锁(row share table lock)(也称为 subshare table lock,SS)。此锁不允许其他事务排他地对子表加锁,但允许对父表及子表执行 DML 操作

父表、子表 主外键关系