2012-02-15 17 views
5

Rozważmy następujący (uproszczony) Położenie:Plan wykonania klucza obcego 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) 
); 

Nie ma indeks na CHILD.PARENT_ID, więc modyfikowanie/usuwanie PARENT jest drogie (Oracle musi wykonać pełny skan tabeli na CHILD egzekwować więzów integralności). Jednak plan wykonania dla następującym stwierdzeniem ...

DELETE FROM PARENT WHERE PARENT_ID = 1 

... nie pokazuje skan tabeli (SYS_C0070229 jest indeks na PARENT.PARENT_ID):

query plan

wiem, istnieją sposoby do see all unindexed FOREIGN KEYs, ale byłoby jeszcze lepiej, gdybym mógł zostać "ostrzeżony" o potencjalnym problemie w samym planie wykonania zapytania (BTW, MS SQL Server i ewentualnie inne bazy danych to robią).

Czy to możliwe w Oracle?

Używam Oracle 10.2, jeśli to ma znaczenie.

+1

Nie jestem pewien, czy masz dostęp do tego, czy nie, ale SQL Oracle Analyse (http://docs.oracle.com/html/A86647_01/vmqintro.htm) ma kilka zaawansowanych funkcji do analizy i strojenia SQL. –

+0

@ZackMacomber Dzięki, nie jestem zaznajomiony z tym, ale upewnię się, że się uczę. Czy rzeczywiście zrobi to, o co prosiłem? –

Odpowiedz

4

I zmieniły swoje ograniczenia, aby dodać „ON DELETE CASCADE”, bez której Oracle zgłosi błąd. (Domyślna wartość dla kluczowych łamanie zagranicznych jest usunięcie ograniczenia)

Uważam, że odpowiedź na Twoje pytanie to "NIE", Oracle nie ostrzega cię o niepotwierdzonej kolumnie klucza obcego. W praktyce większość takich kolumn jest indeksowana, ponieważ w ten sposób łączysz się z rodzicem z dzieckiem.

Jeśli chcesz udowodnić komuś, że brak indeksu spowoduje problemy z blokowaniem i eskalacją (coś niezbyt pożądanego), możesz po prostu wyłączyć blokadę tabeli i pokazać błąd.

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 

I dla wyjaśnienia planu pytanie, jak inni zwrócili uwagę, SQL, aby usunąć z tabeli podrzędnej jest rekurencyjne SQL i nie jest pokazany w planie wyjaśnić.

Jeśli śledzisz sesję, zobaczysz rekursywny 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)' 

Przydatne linki: http://www.oracle-base.com/articles/10g/SQLTrace10046TrcsessAndTkprof10g.php

2

Kwerendą wymuszającą integralność referencyjną jest "rekursywny sql" (tj. Generowany przez Oracle), dlatego nie pojawi się w planie wyjaśniającym. Jeśli faktycznie wykonasz operację i prześledzisz ją, zobaczysz również rekurencyjny sql.

+0

"SET AUTOTRACE ON" nadal pokazuje ten sam plan wykonania. Czy jest coś szczególnego, co powinienem zrobić, aby zobaczyć ten "rekurencyjny SQL"? –

+0

@Branko - aby wyświetlić rekursywny SQL, należy uruchomić śledzenie sesji. –