关于Oracle外键列上是否需要索引问题
关于Oracle外键列上是否需要索引问题外键列上缺少索引会带来两个问题,限制并发性、影响性能。而这两个问题中的任意一个都可能会造成严重性能问题。无论是Oracle的官方文档,还是在Tom的书中都说明了两种情况下可以忽略外键上的索引。其实我认为不需要那么麻烦,与增加一个索引所带来的性能开销和磁盘空间开销相比,缺失索引可能引发的问题要严重得多。因此,我会选择在所有的外键列上添加索引,虽然可能导致创建了部分多余的索引,但是这样相除了外键约束由于确实索引所带来的性能问题和并发性问题。如果外键列上缺少索引,从主表关联子表的查询就只能对子表选择全表扫描的查询,这是显而易见的问题:SQL> CREATE TABLE T_P (ID NUMBER, NAME VARCHAR2(30));表已创建。SQL> ALTER TABLE T_P ADD PRIMARY KEY (ID);表已更改。SQL> CREATE TABLE T_C (ID NUMBER, FID NUMBER, NAME VARCHAR2(30));表已创建。SQL> ALTER TABLE T_C ADD CONSTRAINT FK_T_C FOREIGN KEY (FID) REFERENCES T_P (ID);表已更改。SQL> INSERT INTO T_P SELECT ROWNUM, TABLE_NAME FROM ALL_TABLES;已创建884行。SQL> INSERT INTO T_C SELECT ROWNUM, MOD(ROWNUM, 884) + 1, OBJECT_NAME FROM ALL_OBJECTS;已创建30339行。SQL> COMMIT;提交完成。SQL> SELECT A.ID, A.NAME, B.NAME2 FROM T_P A, T_C B3 WHERE A.ID = B.FID4 AND A.ID = 880;ID NAME NAME---------- ------------------------------ ------------------------------880 T_COMPRESS /eb2b6b5_Options1880 T_COMPRESS DATE880 T_COMPRESS DEF$_SCHEDULE880 T_COMPRESS GV_$SESSION_EVENT...已选择34行。执行计划----------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE1 0 MERGE JOIN2 1 TABLE ACCESS (BY INDEX ROWID) OF 'T_P'3 2 INDEX (UNIQUE SCAN) OF 'SYS_C002964' (UNIQUE)4 1 FILTER5 4 TABLE ACCESS (FULL) OF 'T_C'统计信息----------------------------------------------------------0 recursive calls0 db block gets190 consistent gets0 physical reads0 redo size1829 bytes sent via SQL*Net to client394 bytes received via SQL*Net from client4 SQL*Net roundtrips to/from client0 sorts (memory)0 sorts (disk)34 rows processed由于缺少索引,上面的这个关联查询只能采用MERGE JOIN,而如果联立了外键列上的索引:SQL> CREATE INDEX IND_T_C_FID ON T_C (FID);索引已创建。SQL> SELECT A.ID, A.NAME, B.NAME2 FROM T_P A, T_C B3 WHERE A.ID = B.FID4 AND A.ID = 880;ID NAME NAME---------- ------------------------------ ------------------------------880 T_COMPRESS /e1538703_EntryInfoImpl880 T_COMPRESS /7b832daf_ObjectStreamClassCom880 T_COMPRESS java/awt/peer/ScrollbarPeer880 T_COMPRESS /1982bd95_PermissionsEnumerato...已选择34行。执行计划----------------------------------------------------------0 SELECT STATEMENT Optimizer=CHOOSE1 0 NESTED LOOPS2 1 TABLE ACCESS (BY INDEX ROWID) OF 'T_P'3 2 INDEX (UNIQUE SCAN) OF 'SYS_C002964' (UNIQUE)4 1 TABLE ACCESS (BY INDEX ROWID) OF 'T_C'5 4 INDEX (RANGE SCAN) OF 'IND_T_C_FID' (NON-UNIQUE)统计信息----------------------------------------------------------0 recursive calls0 db block gets42 consistent gets1 physical reads0 redo size1829 bytes sent via SQL*Net to client394 bytes received via SQL*Net from client4 SQL*Net roundtrips to/from client0 sorts (memory)0 sorts (disk)34 rows processed上面是影响性能的例子,下面看看外键列索引对并发性的影响:SQL> SET AUTOT OFFSQL> SELECT * FROM T_P WHERE ID < 5;ID NAME---------- ------------------------------1 SEG$2 CLU$3 OBJ$4 FILE$SQL> SELECT * FROM T_C WHERE ID < 5;ID FID NAME---------- ---------- ------------------------------1 2 /1005bd30_LnkdConstant2 3 /10076b23_OraCustomDatumClosur3 4 /10297c91_SAXAttrList4 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');已创建上一个:ORA-01093: ALTER DATABASE CLOSE only permitted with no sessions connected解决方法
下一个:Oracle主键、唯一键与唯一索引的区别
- 更多Oracle疑问解答:
- 运行exp备份oracle数据库提示oracle-12154错误
- 有没有,生产Oracle Rman 备份脚本的工具啊!
- 初学orcle,希望有大大帮忙解说一下详细步骤,从登录oracle到创建表的过程
- oracle语句问题:一张user表,三个字段,id,name,time,插入记录比如:张三2007,李四2008,张三2011
- 如何写一个ORACLE触发器同步两个表中的数据?
- oracle 如何查看一个服务器上有多少个数据库.
- oracle 创建包的时候错误 求解
- oracle 重复列的问题
- oracle 中如何查处2星期前的数据
- 请教oracle数据库安装中的问题
- 请问谁能提供给我标准的oracle ERP的数据库表结构并详细说明各表主要的作用?
- 安装oracle遇到的问题 invalid entry CRC (expected 0x3e12e795 but got 0x9db0e9fd)
- 我的是ORACLE 10G,在RMAN中如何按指定的时间恢复数据文件啊?
- oracle为什么没有自动增长列
- oracle快捷键都有哪些啊?