Oracle how child table behave when data from parent table is modified? - oracle

Scenario: We have table A (Parent Table) referring to table B (Child Table) and also we have Foreign Key Index for every Foreign Key.
Operation: Now when any user is deleting a row from table A then table B is getting locked even if there are no referring record in child table. Because of this other user cannot do anything on table A anymore since the table is locked.
Understanding: I suppose when there are some child record exists in table B then the selected row should only be locked if the parent record is involved in some transaction and other users can still work on other rows of table A.
Question: How does it work when we have foreign key and foreign key index are created but there are no child record exists. The whole table is still locked? If yes how to get rid of it then?
Note: I am using Oracle 12c.

You should have indexes on all foreign keys, otherwise you'll get TM table locks:
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:292016138754
http://www.oaktable.net/content/tm-locking-checking-missing-indexes-foreign-key-constraints
Now when any user is deleting a row from table A then table B is getting locked even if there are no referring record in child table.
If you have index on foreign key in child table, you get only TX row locks in child table. If you foerign key is not indexes, you get TM table lock on whole child table.

Related

Update on any child table's row is locking entire parent table in oracle

I have a parent table PT having below columns
PT_ID,
PT1_ID,
PT2_ID,
PT_COMMENT
Another child table CT is there having below columns
CT_ID,
PT_ID,
PT1_ID,
PT2_ID,
CT_COMMENT
There are rows in CT table where foreign key columns are having null values (means no value)
If we are updating the CT_COMMENT in CT table for more than 320 rows and at the same time in another seesion we are trying to update one parent table comment in PT_COMMENT column which is not happening until child records update is not getting completed.
Here same Parent table PT_ID row is not getting updated in child table CT, Though Parent Table is getting stuck.
Can anyone help me out to figure it out the reason for locking?
Thank in advance
The index was not appropriate, hence the parent table was getting locked.
After the recreation of an index, now it is working.

Oracle lock issue - ORA-00054: resource busy - while creating a foreign key

Initial situation:
A table PARENT_TABLE with a primary key on its column PK_COL.
A table CHILD_TABLE1 with a foreign key on PARENT_TABLE(PK_COL).
I insert a line into CHILD_TABLE1 in a transaction and do not commit.
Then I try to create a table CHILD_TABLE2 symmetrical to CHILD_TABLE1 in another session.
But an ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired is raised when I create the foreign key, because of the ongoing insertion in CHILD_TABLE1.
I don't understand why Oracle is preventing the foreign key creation: there is no modification performed on PARENT_TABLE.
Please help.
To reproduce under sqlplus:
set autocommit off
create table PARENT_TABLE(PK_COL varchar(10));
alter table PARENT_TABLE add constraint PK_CONSTRAINT primary key (PK_COL);
insert into PARENT_TABLE values ('foo');
commit;
create table CHILD_TABLE1(CHILD_PK_COL varchar(10), FK_COL varchar(10));
alter table CHILD_TABLE1 add constraint CHILD_TABLE1_CONSTRAINT foreign key (FK_COL) references PARENT_TABLE(PK_COL);
create index CHILD_TABLE1_INDEX on CHILD_TABLE1(FK_COL);
insert into CHILD_TABLE1 values ('bar', 'foo');
In another console:
alter session set ddl_lock_timeout=10;
create table CHILD_TABLE2(CHILD_PK_COL varchar(10), FK_COL varchar(10));
alter table CHILD_TABLE2 add constraint CHILD_TABLE2_CONSTRAINT foreign key (FK_COL) references PARENT_TABLE(PK_COL);
Funny: with NOVALIDATE in CHILD_TABLE2_CONSTRAINT creation, the execution is hanging...
You are not modifying something in the parent table. But you're
actually, trying to refer its primary key in your child table. Before
establishing a relationship or any DDL with table, it has to be free
of locks.
So, before creating this constraint, Oracle do check for existing locks over the referred table(PARENT_TABLE). A lock over a table(Table Level Lock,in this context) is actually for a reason to adhere to the ACID properties.
One best example to understand its importance is ON DELETE CASCADE which means if a record in the parent table is deleted, then the corresponding records in the child table will automatically be deleted.
So, when there's a uncommitted insert/update/delete over the child table referring a parent table. No other referential constraint can be created to the parent. Just to avoid a deadlock or chaos.
To be more crisp, when you have an uncommitted insert in your child table.
There's a lock over your parent table as well. So all other further DDLs referring it will be made wait.
You can use this query to check the same.
SELECT c.owner,
c.object_name,
c.object_type,
b.sid,
b.serial#,
b.status,
b.osuser,
b.machine
FROM v$locked_object a ,
v$session b,
dba_objects c
WHERE b.sid = a.session_id
AND a.object_id = c.object_id;
I added the LOCKED_MODE explanation in you query:
DECODE(a.LOCKED_MODE, 0,'NONE', 1,'NULL', 2,'ROW SHARE (RS/SS)', 3,'ROW EXCLUSIVE (RX/SX)', 4,'SHARE (S)', 5,'SHARE ROW EXCLUSIVE (SRX/SSX)', 6,'EXCLUSIVE (X)', NULL) LOCK_MODE.
Here is the result:
OBJECT_NAME OBJECT_TYPE LOCK_MODE SID SERIAL# STATUS
------------------------------ ------------------- ----------------------------- ---------- ---------- --------
PARENT_TABLE TABLE ROW EXCLUSIVE (RX/SX) 71 8694 INACTIVE
CHILD_TABLE1 TABLE ROW EXCLUSIVE (RX/SX) 71 8694 INACTIVE
RX/SX is a table lock so it prevents any DDL operation (That seems to be said in the doc). This lock is used on both parent and child. I suppose that the lock is added on parent to at least prevent it from being deleted so we would lost the pending update on the child table.
That said, I still have no solution. Suppose that the parent table is a manufacturer. There is a child car table and we are inserting plenty of new cars in that table on the fly. There is a foreign key from car to manufacturer. Now there is a new product that we want to manage: "bicycles". So we want to create a bicycle table similar to car. But we cannot create the table as we are performing insertions in car. Seems a very simple use case... How to support it?
=====
Edit:
There might be no solution. Here is a guy with the same issue.

How to drop Parent table without deleting or dropping constraints on child table in Oracle

I have two tables one is Parent and Child. Parent table have primary constraint on it and the Child table have a foreign key constraint on it. Now I want to drop the Parent table without deleting or dropping constraints which are there on child table.
I have tried disabling the constraints on both parent and child table and tried to drop the parent table. But still I was not able to drop the Parent table.
And If the delete the primary constraint on the parent delete, then it also drops the foreign key constraint on the child table.
Please if any one can help me out.
Thanks.
You can't drop a parent table if you have a child table with a foreign key constraint in place, unless you specify the CASCADE CONSTRAINTS clause:
DROP TABLE P CASCADE CONSTRAINTS;
This command drops the FK constraint too.
Deleting a table will necessarily drop all constraints related to this table. if a table is referenced by this table, you will have to drop those constraints first before to avoid rules violation.
*The oracle documentation says: *
http://docs.oracle.com/cd/B28359_01/server.111/b28310/tables010.htm#ADMIN01505
The following statement drops the t table:
DROP TABLE t;
If the table to be dropped contains any primary or unique keys referenced by foreign keys of other tables and you intend to drop the FOREIGN KEY constraints of the child tables, then include the CASCADE clause in the DROP TABLE statement, as shown below:
DROP TABLE t CASCADE CONSTRAINTS;
Weird... if you disabled correctly the constraints you should be able to delete parent table without any error.
:|

Oracle Index - full table scan/lock

Found this here:
In general, consider creating an index on a column in any of the following situations:
A referential integrity constraint exists on the indexed column or
columns. The index is a means to avoid a full table lock that would
otherwise be required if you update the parent table primary key,
merge into the parent table, or delete from the parent table.
I don't understand why a full table lock would occurr in such situation. I would've thought that if I tried to delete/update the primary key in the parent table that a full table scan would be performed on the child table.
Where does the lock come from?
Have a look at this Tom Kyte blog entry. In it, he refers to the Oracle documentation, where this explanation is offered:
Prevents a full table lock on the child table. Instead, the database acquires a row lock on the index.
Removes the need for a full table scan of the child table. As an illustration, assume that a user removes the record for department 10 from the departments table. If employees.department_id is not indexed, then the database must scan employees to see if any employees exist in department 10.
In the first scenario, if the column is not indexed, the entire table must be locked because Oracle does not know which rows must be updated in the child table. With an index, Oracle can identify the rows in question and just lock them. Without the full table lock, it would be possible to modify the parent and have another session modify the child to something that violated the constraint.

Oracle - Deleting row from child table locks parent table

We have deadlock issue in Oracle 11.2g. One potential reason why deadlock occurs is deleting from child table locks parent table. I searched from oracle documentations, and did't find any specification this kind of lock. Any explanation or reference of documentation would be greatly appreciated.
Here is the code.
CREATE TABLE table_parent (a NUMBER PRIMARY KEY);
CREATE TABLE table_child (b NUMBER, a NUMBER,PRIMARY KEY (b), CONSTRAINT fk_relation FOREIGN KEY (a) REFERENCES table_parent(a));
INSERT INTO table_parent VALUES (1);
INSERT INTO table_parent VALUES (2);
INSERT INTO table_child VALUES (1,1);
INSERT INTO table_child VALUES (2,1);
INSERT INTO table_child VALUES (3,1);
INSERT INTO table_child VALUES (4,1);
COMMIT;
Then delete 1 record from child table.
DELETE FROM table_child WHERE b=4;
When we look V$LOCK table before executing commit. There is two new lock that 'table_child' and 'table_parent' in type of 'TM'.
Here is the query to look V$LOCK table.
SELECT O.OWNER, O.OBJECT_ID, O.OBJECT_NAME, O.OBJECT_TYPE, L.TYPE
FROM DBA_OBJECTS O, V$LOCK L
WHERE O.OBJECT_ID = L.ID1;
The question is why 'table_parent' has been locked?
For maintaining constraints that 'span multiple rows', which is the case for a foreign key, there are moments when one (ie. the DBMS) needs to serialize transactions. The moments at which serialization is required depend one-on-one on the type of changes that a transaction performs on the involved tables. Theoretically (in a DBMS that offers snapshot isolation, which is what Oracle does), only if the type of change is such that it could potentially violate the multi-row constraint, would the DBMS need to automatically serialize transactions (for instance by acquiring various types of locks).
Now in the case of a foreign key, one needs to ask oneself: when can a foreign key be violated? There are four scenarios.
a parent row is deleted: will violate FK if child-rows still exist.
a parent row's key is updated: will violate FK if child-rows till 'point to' old value of key.
a child row is inserted: will violate FK if row points-to non-existent parent-row.
a child row's fk-column value is updated: will violate FK if new column value points to non-existent parent-row.
All other types of transactions on the (2) tables involved can never violate the FK. So in your case, a child row is deleted, no serialization should be necessary. However Oracle probably has some 'implementation specific' reason, which forces it to do acquire some kind of lock.
I've seen a different scenario where Oracle performs this kind of "unnecessary" locking too: you can find it here https://forums.oracle.com/forums/thread.jspa?messageID=10050753&#10050753
Toon
Add an index on the table_child(a) column -- you always index foreign key columns for just this reason.
An answer to this is explained with examples here http://www.oraclebin.com/2012/12/what-is-deadlock-in-oracle.html

Resources