关于Oracle外键列上是否需要索引问题(二)
------------
1 SEG$
2 CLU$
3 OBJ$
4 FILE$
SQL> SELECT * FROM T_C WHERE ID < 5;
ID FID NAME
---------- ---------- ------------------------------
1 2 /1005bd30_LnkdConstant
2 3 /10076b23_OraCustomDatumClosur
3 4 /10297c91_SAXAttrList
4 5 /103a2e73_DefaultEditorKitEndP
下面在另一个会话中删除子表的一条记录:
SQL> SET SQLP 'SQL2> '
SQL2> DELETE T_C WHERE ID = 2;
已删除 1 行。
删除了一条为2的子表级联,其对应的主表记录ID为3,下面尝试在第一个会话新增一条ID为1000的记录,然后删除这条记录:
SQL> INSERT INTO T_P VALUES (1000, 'A');
已创建 1 行。
SQL> DELETE T_P WHERE ID = 1000;
已删除 1 行。
SQL> ROLLBACK;
回退已完成。
可以看到,并没有发生锁表的情况,这是因为子表外键列上有索引,删除主表的记录时,只会锁定子表参考主表的对应记录。
会话二回滚:
SQL2> ROLLBACK;
回退已完成。
下面删除外键索引:
SQL> DROP INDEX IND_T_C_FID;
索引已删除。
重复刚才的操作,在另一个会话执行删除操作:
SQL2> DELETE T_C WHERE ID = 2;
已删除 1 行。
在会话一重复插入和删除操作:
SQL> INSERT INTO T_P VALUES (1000, 'A');
已创建 1 行。
SQL> DELETE T_P WHERE ID = 1000;
这时会话被锁住,因为缺少了外键索引后,主表删除或更新记录会导致子表整个表被锁,而这会导致严重的
系统并发问题。
SQL2> ROLLBACK;
回退已完成。
会话2回滚后,会话1的删除操作才可以继续执行:
已删除 1 行。
可能有些人会认为,系统中不存在删除而不会导致这个问题,其实不仅是删除,主键列的更新同样可以导致这个问题。
而且这种更新可能是工具帮你自动完成的,因为很多工具会自动生成SQL语句,而在这种生成的SQL语句中,UPDATE的列是表中的所有
列,所以即使主键的值没有发生变化,但是仍然是被更新了:
SQL2> DELETE T_C WHERE ID = 2;
已删除 1 行。
还是删除这条ID为2的子表记录,下面在主表执行一个更新操作:
SQL> UPDATE T_P SET ID = 500 WHERE ID = 500;
可以看到,不管值是否发生了变化,只要主键列被更新,就会导致操作被锁定。
显而易见,不加索引的外键列会造成严重的性能问题,所以除非你有十分的把握,否则还是在外键列上添加索引吧。
设置级关更新/删除
Oracle 级联删除使用格参考式:
CREATE TABLE A001(ID INT PRIMAY KEY,NAME VARCHAR2(20))
CREATE TABLE A002(ID INT REFERENCES A001(ID)ON DELETE CASCADE,AGE NUMBER(2,0))
建立这个表的时候用到ON DELETE CASCADE或ON UPDATE CASCADE。