I don't see any problems with the script because we're talking different things here (this is why I had the index present in the office hours session)
- Without the index - I *do* need locks on the child because ... I don't have the FK index.
- Since 11, we've been doing level 2 locks on tables related by FKs because of some of the niche scenarios, eg online move or index rebuilds whilst there are uncomitted transactions etc etc....I can't remember the specifics, but we need them.
Here's your script with the advantage of seeing v$lock which we don't get in livesql :-(
SQL>
SQL> create table parent (
2 p integer primary key,
3 descr varchar2(10),
4 created date,
5 updated date
6 ) ;
Table created.
SQL>
SQL> create table child (
2 c integer primary key,
3 p integer references parent (p),
4 descr varchar2(10),
5 created date,
6 updated date
7 ) ;
Table created.
SQL>
SQL> create sequence parent_seq ;
Sequence created.
SQL>
SQL> create sequence child_seq ;
Sequence created.
SQL>
SQL> begin
2 insert into parent (p, descr, created) values (parent_seq.nextval, 'p1', sysdate);
3 insert into child (c, p, descr, created) values (child_seq.nextval, parent_seq.currval, 'c1', sysdate);
4 commit;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
SQL>
SQL> -- TEST 1
SQL> -- single trigger on parent, no index on child(p)
SQL> create or replace trigger parent_trg
2 before insert or update on parent
3 for each row
4 begin
5 if inserting then
6 if :new.p is null then
7 :new.p := parent_seq.nextval; --> this row has impact, it will cause the child table to be locked !!!
8 end if;
9 :new.created := sysdate;
10 elsif
11 updating then
12 :new.updated := sysdate;
13 end if;
14 end;
15 /
Trigger created.
SQL>
SQL> -- update parent row & check locks
SQL> update parent
2 set descr = 'pp1'
3 where p = 1 ;
1 row updated.
SQL>
SQL> select locked_mode, object_name
2 from v$locked_object l, all_objects ob
3 where ob.object_id =l.object_id;
LOCKED_MODE OBJECT_NAME
----------- ----------------------------------------
3 PARENT
1 row selected.
SQL>
SQL> rollback;
Rollback complete.
SQL>
SQL>
SQL> -- insert parent row & check locks
SQL> insert into parent (descr)
2 values ('p2') ;
1 row created.
SQL>
SQL> select locked_mode, object_name
2 from v$locked_object l, all_objects ob
3 where ob.object_id =l.object_id;
LOCKED_MODE OBJECT_NAME
----------- ----------------------------------------
3 PARENT
2 CHILD
2 rows selected.
SQL>
SQL> rollback;
Rollback complete.
SQL>
SQL>
SQL> -- TEST 2
SQL> -- separate triggers on parent, no index on child(p)
SQL> drop trigger parent_trg ;
Trigger dropped.
SQL>
SQL> create or replace trigger parent_ins_trg
2 before insert on parent
3 for each row
4 begin
5 if :new.p is null then
6 :new.p := parent_seq.nextval; --> this row has impact, it will cause the child table to be locked !!!
7 end if;
8 :new.created := sysdate;
9 end;
10 /
Trigger created.
SQL>
SQL> create or replace trigger parent_upd_trg
2 before update on parent
3 for each row
4 begin
5 :new.updated := sysdate;
6 end;
7 /
Trigger created.
SQL>
SQL> -- update parent row & check locks
SQL> update parent
2 set descr = 'pp1'
3 where p = 1 ;
1 row updated.
SQL>
SQL> select locked_mode, object_name
2 from v$locked_object l, all_objects ob
3 where ob.object_id =l.object_id;
LOCKED_MODE OBJECT_NAME
----------- ----------------------------------------
3 PARENT
1 row selected.
SQL>
SQL> rollback;
Rollback complete.
SQL>
SQL>
SQL> -- insert parent row & check locks
SQL> insert into parent (descr)
2 values ('p2') ;
1 row created.
SQL>
SQL> select locked_mode, object_name
2 from v$locked_object l, all_objects ob
3 where ob.object_id =l.object_id;
LOCKED_MODE OBJECT_NAME
----------- ----------------------------------------
3 PARENT
2 CHILD
2 rows selected.
SQL>
SQL> rollback;
Rollback complete.
SQL>
SQL>
SQL> -- create index on child(p)
SQL> create index child_ix_p on child(p) ;
Index created.
SQL>
SQL> -- TEST 3
SQL> -- single trigger on parent, with index on child(p)
SQL> drop trigger parent_ins_trg ;
Trigger dropped.
SQL>
SQL> drop trigger parent_upd_trg ;
Trigger dropped.
SQL>
SQL> create or replace trigger parent_trg
2 before insert or update on parent
3 for each row
4 begin
5 if inserting then
6 if :new.p is null then
7 :new.p := parent_seq.nextval; --> this row has impact, it will cause the child table to be locked !!!
8 end if;
9 :new.created := sysdate;
10 elsif
11 updating then
12 :new.updated := sysdate;
13 end if;
14 end;
15 /
Trigger created.
SQL>
SQL> -- update parent row & check locks
SQL> update parent
2 set descr = 'pp1'
3 where p = 1 ;
1 row updated.
SQL>
SQL> select locked_mode, object_name
2 from v$locked_object l, all_objects ob
3 where ob.object_id =l.object_id;
LOCKED_MODE OBJECT_NAME
----------- ----------------------------------------
3 PARENT
3 CHILD
2 rows selected.
SQL>
SQL> rollback;
Rollback complete.
SQL>
SQL>
SQL> -- insert parent row & check locks
SQL> insert into parent (descr)
2 values ('p2') ;
1 row created.
SQL>
SQL> select locked_mode, object_name
2 from v$locked_object l, all_objects ob
3 where ob.object_id =l.object_id;
LOCKED_MODE OBJECT_NAME
----------- ----------------------------------------
3 PARENT
2 CHILD
2 rows selected.
SQL>
SQL> rollback;
Rollback complete.
SQL>
SQL>
SQL> -- TEST 4
SQL> -- separate triggers on parent, with index on child(p)
SQL> drop trigger parent_trg ;
Trigger dropped.
SQL>
SQL> create or replace trigger parent_ins_trg
2 before insert on parent
3 for each row
4 begin
5 if :new.p is null then
6 :new.p := parent_seq.nextval; --> this row has impact, it will cause the child table to be locked !!!
7 end if;
8 :new.created := sysdate;
9 end;
10 /
Trigger created.
SQL>
SQL> create or replace trigger parent_upd_trg
2 before update on parent
3 for each row
4 begin
5 :new.updated := sysdate;
6 end;
7 /
Trigger created.
SQL>
SQL> -- update parent row & check locks
SQL> update parent
2 set descr = 'pp1'
3 where p = 1 ;
1 row updated.
SQL>
SQL> select locked_mode, object_name
2 from v$locked_object l, all_objects ob
3 where ob.object_id =l.object_id;
LOCKED_MODE OBJECT_NAME
----------- ----------------------------------------
3 PARENT
1 row selected.
SQL>
SQL> rollback;
Rollback complete.
SQL>
SQL>
SQL> -- insert parent row & check lock
SQL> insert into parent (descr)
2 values ('p2') ;
1 row created.
SQL>
SQL> select locked_mode, object_name
2 from v$locked_object l, all_objects ob
3 where ob.object_id =l.object_id;
LOCKED_MODE OBJECT_NAME
----------- ----------------------------------------
3 PARENT
2 CHILD
2 rows selected.
SQL>
SQL> rollback;
Rollback complete.
SQL>
SQL>
SQL>