外键会影响 Oracle 的性能吗?

Edd*_*Edd 5 performance oracle foreign-key execution-plan query-performance

无论您是否为外键创建索引(当然应该这样做),拥有外键对 Oracle 数据库的性能有任何影响吗?

我想知道的一个特定领域是它们是否有助于数据库生成更好的查询计划

Chr*_*xon 9

是的。

当在数据库中强制执行 RI 时,优化器可以从查询中删除冗余表。

例如,这里有两个表:

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
);
Run Code Online (Sandbox Code Playgroud)

第二个只包含第一个的 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;
Run Code Online (Sandbox Code Playgroud)

因此,T2 的计数返回与两个表的连接相同的行数:

select count(*) from t2;

COUNT(*)   
      1000 

select count(*)
from   t1
join   t2
on     t1.t1_id = t2.t1_id;

COUNT(*)   
      1000 
Run Code Online (Sandbox Code Playgroud)

但是没有定义 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")
Run Code Online (Sandbox Code Playgroud)

但是在混合中添加一个外键:

alter table t2 add constraint fk foreign key ( t1_id ) references t1 ( t1_id );
Run Code Online (Sandbox Code Playgroud)

它现在知道 t2 中不能有任何 t1 中不存在的 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 |   
------------------------------------------------------------------------------------- 
Run Code Online (Sandbox Code Playgroud)

噗!它消失了!:)