父表、子表 主外键关系

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

 

外键上无索引

 

 

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

 

 

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

 

源文档 <http://www.itpub.net/forum.php?mod=viewthread&tid=1472599>

 

创建测试环境

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.

 

此时子表外键 不加索引

 

脚本1,对 测试表 进行 10000000 UPDATE 操作,模拟并发事务 

[oracle@cuug ~]$ vi test_sql.sql

declare

begin

for i in 4..10000000 loop

update t1 set n1=n1*1 where n1=1;

end loop;

end;

 /

 

脚本2,专门对于SSX( 获得以后 就释放,不容易捕捉,所以使用脚本)

[oracle@cuug ~]$ vi test_sql1.sql

declare

  v1 char(10);

  begin

for i in 1..1000000 loop

  select locked_mode into v1 from v$locked_object where object_id=52886;

  insert into t3 values(v1);

commit;

end loop;

  end;

  /

 

查锁语句

SELECT LK.SID,SE.USERNAME,SE.OSUSER,SE.MACHINE,

DECODE(LK.TYPE,'TX','Transaction','TM','DML','UL','PL/SQL User Lock',LK.TYPE) LOCK_TYPE,

DECODE(LK.LMODE,0,'None',1,'Null',2,'Row-S (SS)',3,'Row-X (SX)',4,'Share',5,'S/Row-X (SSX)',6,'Exclusive',TO_CHAR(LK.LMODE)) MODE_HELD,

DECODE(LK.REQUEST,0,'None',1,'Null',2,'Row-S (SS)',3,'Row-X (SX)',4,'Share',5,'S/Row-X (SSX)',6,'Exclusive',

TO_CHAR(LK.REQUEST)) MODE_REQUESTED,TO_CHAR(LK.ID1) LOCK_ID1,TO_CHAR(LK.ID2) LOCK_ID2,

OB.OWNER,OB.OBJECT_TYPE,OB.OBJECT_NAME,LK.BLOCK,SE.LOCKWAIT

FROM V$LOCK LK, DBA_OBJECTS OB, V$SESSION SE

WHERE LK.TYPE IN ('TM', 'UL')

AND LK.SID = SE.SID

AND LK.ID1 = OB.OBJECT_ID(+);

 

 

 

 

 

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

TEST @ prod >insert into father values(50,'beijing','china');

 

1 row created.

TEST @ prod >col object_id for 99999

TEST @ prod >col object_name for a10

TEST @ prod >select lock1.object_id,obj.object_name,lock1.session_id,lock1.locked_mode from v$locked_object lock1 ,dba_objects obj where lock1.session_id=159 and lock1.object_id=obj.object_id

 

OBJECT_ID OBJECT_NAM SESSION_ID LOCKED_MODE

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

    52874 CHILDEN           159           2

52873 FATHER            159           3

 

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

 

结果二:

 

159    TEST    oracle    cuug    DML    Row-X (SX)    None    52873    0    TEST    TABLE    FATHER  0

159    TEST    oracle    cuug    DML    Row-S (SS)    None    52874    0    TEST    TABLE    CHILDEN    0

 

 

 

 

 

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

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

 

1 row created.

 

TEST @ prod >select lock1.object_id,obj.object_name,lock1.session_id,lock1.locked_mode from v$locked_object lock1 ,dba_objects obj where lock1.session_id=159 and lock1.object_id=obj.object_id;

 

 

 

 

OBJECT_ID OBJECT_NAM SESSION_ID LOCKED_MODE

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

    52786 CHILDEN           159           3

52785 FATHER            159           2

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

 

 

159    TEST    oracle    cuug    DML    Row-S (SS)    None    52873    0    TEST    TABLE    FATHER    0

159    TEST    oracle    cuug    DML    Row-X (SX)    None    52874    0    TEST    TABLE    CHILDEN    0   

 

 

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

TEST @ prod >update father set deptno=deptno*1 ;

 

5 rows updated.

TEST @ prod >select lock1.object_id,obj.object_name,lock1.session_id,lock1.locked_mode from v$locked_object lock1 ,dba_objects obj where lock1.session_id=159 and lock1.object_id=obj.object_id;

 

OBJECT_ID OBJECT_NAM SESSION_ID LOCKED_MODE

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

    52785 FATHER            159           3  

 

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

 

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

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

 

14 rows updated.

 

TEST @ prod >select lock1.object_id,obj.object_name,lock1.session_id,lock1.locked_mode from v$locked_object lock1 ,dba_objects obj where lock1.session_id=159 and lock1.object_id=obj.object_id;

 

OBJECT_ID OBJECT_NAM SESSION_ID LOCKED_MODE

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

    52786 CHILDEN           159           3

52785 FATHER            159           2

 

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

 

 

 

 

 

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

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

 

1 row deleted.

 

TEST @ prod >select lock1.object_id,obj.object_name,lock1.session_id,lock1.locked_mode from v$locked_object lock1 ,dba_objects obj where lock1.session_id=159 and lock1.object_id=obj.object_id;

 

OBJECT_ID OBJECT_NAM SESSION_ID LOCKED_MODE

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

52785 FATHER            159           3

 

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

 

 

 

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

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

 

0 rows deleted.

 

TEST @ prod >select lock1.object_id,obj.object_name,lock1.session_id,lock1.locked_mode from v$locked_object lock1 ,dba_objects obj where lock1.session_id=159 and lock1.object_id=obj.object_id;

 

OBJECT_ID OBJECT_NAM SESSION_ID LOCKED_MODE

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

    52786 CHILDEN           159           3

52785 FATHER            159           2

 

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

 

 

 

 

 

 

 

 

 

 

 

 

子表的外键字段添加索引

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

 

Index created.

 

TEST @ 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

 

 

 

 

 

 

 

 

 

 

 

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

TEST @ prod >insert into father values(50,'beijing','china');

 

1 row created.

TEST @ prod >col object_id for 99999

TEST @ prod >col object_name for a10

TEST @ prod >select lock1.object_id,obj.object_name,lock1.session_id,lock1.locked_mode from v$locked_object lock1 ,dba_objects obj where lock1.session_id=159 and lock1.object_id=obj.object_id

 

OBJECT_ID OBJECT_NAM SESSION_ID LOCKED_MODE

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

    52786 CHILDEN           159           2

52785 FATHER            159           3

 

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

 

 

 

 

 

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

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

 

1 row created.

 

TEST @ prod >select lock1.object_id,obj.object_name,lock1.session_id,lock1.locked_mode from v$locked_object lock1 ,dba_objects obj where lock1.session_id=159 and lock1.object_id=obj.object_id;

 

OBJECT_ID OBJECT_NAM SESSION_ID LOCKED_MODE

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

    52786 CHILDEN           159           3

52785 FATHER            159           2

 

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

 

 

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

TEST @ prod >update father set deptno=deptno*1 ;

 

5 rows updated.

TEST @ prod >select lock1.object_id,obj.object_name,lock1.session_id,lock1.locked_mode from v$locked_object lock1 ,dba_objects obj where lock1.session_id=159 and lock1.object_id=obj.object_id;

 

OBJECT_ID OBJECT_NAM SESSION_ID LOCKED_MODE

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

    52785 FATHER            159           3  

 

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

 

 

 

 

 

 

 

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

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

 

14 rows updated.

 

TEST @ prod >select lock1.object_id,obj.object_name,lock1.session_id,lock1.locked_mode from v$locked_object lock1 ,dba_objects obj where lock1.session_id=159 and lock1.object_id=obj.object_id;

 

OBJECT_ID OBJECT_NAM SESSION_ID LOCKED_MODE

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

    52786 CHILDEN           159           3

52785 FATHER            159           2

 

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

 

 

 

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

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

 

1 row deleted.

 

TEST @ prod >select lock1.object_id,obj.object_name,lock1.session_id,lock1.locked_mode from v$locked_object lock1 ,dba_objects obj where lock1.session_id=159 and lock1.object_id=obj.object_id;

 

OBJECT_ID OBJECT_NAM SESSION_ID LOCKED_MODE

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

    52786 CHILDEN           159           2

52785 FATHER            159           3

 

结论:

 

 

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

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

 

0 rows deleted.

 

TEST @ prod >select lock1.object_id,obj.object_name,lock1.session_id,lock1.locked_mode from v$locked_object lock1 ,dba_objects obj where lock1.session_id=159 and lock1.object_id=obj.object_id;

 

OBJECT_ID OBJECT_NAM SESSION_ID LOCKED_MODE

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

    52786 CHILDEN           159           3

52785 FATHER            159           2

 

结论:

 

 

 

 

 

 

 

 

 

 

结论:

 

子表外键 未创建索引

 

 

 

 

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 lockSSX)。此锁能够阻止其他事务对子表执行 DML 操作。SSX 锁在获得后立即释放。如果父表中有多个主键值被更新或删除,对每行执行 DML 操作时都需要对子表进行一次加锁及解锁操作。

 

 

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

 

 

 

 

有索引

TEST @ prod >select * from v$lock where sid=142;

 

ADDR     KADDR                  SID  TY          ID1           ID2      LMODE        REQUEST       CTIME      BLOCK

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

2D1C3F90 2D1C3FA8        142 TM      52883          0             3                       0               143          0

2D1C403C 2D1C4054        142 TM      52886          0             2                       0               143          0

2D231408 2D231524        142 TX     131095       4971          6                       0               143          0

 

没索引

TEST @ prod >select * from v$lock where sid=142;

 

ADDR     KADDR                                 SID          TY             ID1        ID2      LMODE    REQUEST  CTIME      BLOCK

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

2D1C3F90        2D1C3FA8        142        TM        52883            0             3               0                  275        0

2D1C403C        2D1C4054        142        TM        52886            0             4               0                     0        0

2D231408        2D231524        142        TX        393235        4991              6                0                  275        0

 

 

 

创建时间:2022-03-30 20:55
浏览量:0