План выполнения внешнего ключа Oracle? - PullRequest
5 голосов
/ 16 февраля 2012

Рассмотрим следующую (упрощенную) ситуацию:

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 необходимо выполнить полное сканирование таблицы на * 1006)* для обеспечения ссылочной целостности).Тем не менее план выполнения для следующего оператора ...

DELETE FROM PARENT WHERE PARENT_ID = 1

... не показывает сканирование таблицы (SYS_C0070229 - это индекс для PARENT.PARENT_ID):

query plan

Я знаю, что есть способы увидеть все неиндексированные ИНОСТРАННЫЕ КЛЮЧИ , но было бы еще лучше, если бы меня «предупредили» о потенциальной проблеме в самом плане выполнения запроса (кстати, MSSQL Server и, возможно, другие базы данных делают это).

Возможно ли это в Oracle?

Я использую Oracle 10.2, если это имеет значение.

Ответы [ 2 ]

4 голосов
/ 16 февраля 2012

Я изменил ваше ограничение, добавив «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 голосов
/ 16 февраля 2012

Запросом для обеспечения ссылочной целостности является «рекурсивный sql» (т. Е. Сгенерированный Oracle), поэтому он не будет отображаться в плане объяснения.Если вы действительно выполните операцию и отследите ее, вы также увидите рекурсивный sql.

...