2012-02-15 100 views
5

考虑以下(简单的)情况:Oracle外键执行计划?

CREATE TABLE PARENT (
    PARENT_ID INT PRIMARY KEY 
); 

CREATE TABLE CHILD (
    CHILD_ID INT PRIMARY KEY, 
    PARENT_ID INT NOT NULL, 
    FOREIGN KEY (PARENT_ID) REFERENCES PARENT (PARENT_ID) 
); 

上有CHILD.PARENT_ID没有索引,所以修改/删除PARENT昂贵(Oracle需要做CHILD全表扫描强制执行引用完整性)。然而,对于下面的语句的执行计划...

DELETE FROM PARENT WHERE PARENT_ID = 1 

...不显示表扫描(SYS_C0070229是PARENT.PARENT_ID指数):

query plan

我知道有办法到see all unindexed FOREIGN KEYs,但如果我可以在查询执行计划本身(顺便说一句,MS SQL Server和其他可能的数据库做)的一个潜在问题的“警告”会更好。

这有可能在甲骨文?

我使用的是Oracle 10.2,如果该事项。

+1

我不知道如果你有机会到这个与否,但甲骨文的SQL分析(http://docs.oracle.com/html/A86647_01/vmqintro.htm )具有一些用于SQL分析和调优的强大功能。 – 2012-02-15 21:41:56

+0

@ZackMacomber谢谢,我不熟悉它,但我会确保我学习。它实际上会做我所问的吗? – 2012-02-15 22:36:30

回答

4

我已经改变了你的约束添加的“ON DELETE CASCADE”,没有它,Oracle将引发一个错误。(对于外键冲突的默认值是删除限制)

我相信回答你的问题是“否”,Oracle不会对未索引的外键列提出警告。在实践中,大多数这样的列都被编入索引,因为这是您将如何将父母加入孩子的方式。

如果你想证明给别人,不具有一定的折射率会导致锁定问题和升级(不是东西非常可取的),你可以简单地禁用表锁,并显示错误。

SQL> alter table child disable table lock; 

Table altered. 

SQL> delete from parent where parent_id = 10; 
delete from parent where parent_id = 10 
      * 
ERROR at line 1: 
ORA-00069: cannot acquire lock -- table locks disabled for CHILD 

而对于解释计划的问题,正如其他人所指出的那样,SQL从子表中删除是一个递归SQL和解释计划没有显示。

如果您跟踪会话,你会看到递归SQL。

1* alter session set SQL_TRACE = TRUE 
SQL>/

Session altered. 

SQL> delete from parent where parent_id = 10; 

1 row deleted. 

SQL> commit; 

Commit complete. 

SQL> alter session set SQL_TRACE=FALSe; 

Session altered. 

===================== 
PARSING IN CURSOR #2 len=39 dep=0 uid=65 oct=7 lid=65 tim=763167901560 hv=3048246147 ad='3160891c' 
delete from parent where parent_id = 10 
END OF STMT 
PARSE #2:c=0,e=61,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=763167901555 
===================== 
PARSING IN CURSOR #1 len=48 dep=1 uid=0 oct=7 lid=0 tim=763167976106 hv=2120075951 ad='26722c20' 
delete from "RC"."CHILD" where "PARENT_ID" = :1 
END OF STMT 
PARSE #1:c=0,e=42,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=763167976100 
EXEC#1:c=0,e=291,p=0,cr=7,cu=7,mis=0,r=2,dep=1,og=4,tim=763168080347 
EXEC#2:c=0,e=130968,p=0,cr=8,cu=14,mis=0,r=1,dep=0,og=1,tim=763168091605 
STAT #2 id=1 cnt=1 pid=0 pos=1 obj=0 op='DELETE PARENT (cr=8 pr=0 pw=0 time=130887 us)' 
STAT #2 id=2 cnt=1 pid=1 pos=1 obj=58703 op='INDEX UNIQUE SCAN SYS_C006951 (cr=1 pr=0 pw=0 time=19 us)' 
STAT #1 id=1 cnt=0 pid=0 pos=1 obj=0 op='DELETE CHILD (cr=7 pr=0 pw=0 time=233 us)' 
STAT #1 id=2 cnt=2 pid=1 pos=1 obj=58704 op='TABLE ACCESS FULL CHILD (cr=7 pr=0 pw=0 time=76 us)' 

相关链接:http://www.oracle-base.com/articles/10g/SQLTrace10046TrcsessAndTkprof10g.php

2

执行该引用完整性的查询是“递归SQL”(即,由Oracle生成),因此不会在解释计划显示。如果你真的执行了操作并跟踪它,你也会看到递归的sql。

+0

“SET AUTOTRACE ON”仍显示相同的执行计划。有什么特别的,我应该做的,看看这个“递归SQL”? – 2012-02-15 22:33:45

+0

@Branko - 要查看递归SQL,您需要在会话上运行跟踪。 – 2012-02-16 04:57:50