外部キーのインデックスを作成するかどうか(当然のことですが)に関係なく、外部キーがあるとOracleデータベースのパフォーマンスに影響がありますか?
私が疑問に思っていた特定の領域は、データベースがより良いクエリプランを作成するのに役立つかどうかでした
はい。
データベースにRIが適用されている場合、オプティマイザはクエリから冗長なテーブルを削除できます。
たとえば、次の2つのテーブルがあります。
create table t1 (
t1_id int not null primary key
);
create table t2 (
t2_id int not null primary key,
t1_id int not null
);
2番目には、最初のt1_idsのみが含まれます。
insert into t1
select level from dual
connect by level <= 100;
insert into t2
select rownum, t1_id
from t1, (
select * from dual connect by level <= 10
);
commit;
したがって、T2のカウントは、2つのテーブルの結合と同じ数の行を返します。
select count(*) from t2;
COUNT(*)
1000
select count(*)
from t1
join t2
on t1.t1_id = t2.t1_id;
COUNT(*)
1000
しかし、FKは定義されていません:(
したがって、オプティマイザはこれを知りません。また、クエリを実行するときに両方のテーブルにアクセスする必要があります。
set serveroutput off
select /*+ gather_plan_statistics */count(*)
from t1
join t2
on t1.t1_id = t2.t1_id;
COUNT(*)
1000
select *
from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST'));
PLAN_TABLE_OUTPUT
SQL_ID 8p235qbxm8yn0, child number 0
-------------------------------------
select /*+ gather_plan_statistics */count(*) from t1 join t2 on
t1.t1_id = t2.t1_id
Plan hash value: 3484656271
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 10 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 10 |
| 2 | NESTED LOOPS | | 1 | 1000 | 1000 |00:00:00.01 | 10 |
| 3 | TABLE ACCESS FULL| T2 | 1 | 1000 | 1000 |00:00:00.01 | 6 |
|* 4 | INDEX UNIQUE SCAN| SYS_C0014412 | 1000 | 1 | 1000 |00:00:00.01 | 4 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("T1"."T1_ID"="T2"."T1_ID")
しかし、外部キーをミックスに追加します。
alter table t2 add constraint fk foreign key ( t1_id ) references t1 ( t1_id );
そして、t1に存在しないt2のt1_id値は存在できないことがわかります。したがって、t1は無視できます。
select /*+ gather_plan_statistics */count(*)
from t1
join t2
on t1.t1_id = t2.t1_id;
COUNT(*)
1000
select *
from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST'));
PLAN_TABLE_OUTPUT
SQL_ID 8p235qbxm8yn0, child number 0
-------------------------------------
select /*+ gather_plan_statistics */count(*) from t1 join t2 on
t1.t1_id = t2.t1_id
Plan hash value: 476902662
-------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 6 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 6 |
| 2 | TABLE ACCESS FULL| T2 | 1 | 1000 | 1000 |00:00:00.01 | 6 |
-------------------------------------------------------------------------------------
ひどい!なくなった! :)