具有或不具有唯一列的唯一索引性能

Unique index performance with or without unique column

当唯一索引列对相关列也有唯一约束时,性能是否有任何差异?

我知道唯一索引和非唯一索引在性能上存在差异。

但我的问题是,如果列同时具有唯一约束和唯一索引,以及只有唯一索引而没有唯一约束,性能上是否会有差异?

另一个问题是,列统计信息对唯一索引的使用有影响吗?

Oracle 数据库策略具有(唯一)索引的唯一约束。

检查重复条目、查询table等时,数据库将使用索引。不是约束。所以在大多数情况下,性能会相同:

create table t (
  c1 int, c2 int
);

alter table t 
  add constraint u 
  unique ( c1 );
  
create unique index ui 
  on t ( c2 );
  
insert into t
with rws as (
  select level x from dual
  connect by level <= 10000
)
  select x, x from rws;
  
commit;

exec dbms_stats.gather_table_stats ( user, 't' ) ;

alter session set statistics_level = all;
set serveroutput off

select * from t
where  c1 = 1;

select * 
from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST'));

----------------------------------------------------------------------------------------------    
| Id  | Operation                   | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |    
----------------------------------------------------------------------------------------------    
|   0 | SELECT STATEMENT            |      |      1 |        |      1 |00:00:00.01 |       3 |    
|   1 |  TABLE ACCESS BY INDEX ROWID| T    |      1 |      1 |      1 |00:00:00.01 |       3 |    
|*  2 |   INDEX UNIQUE SCAN         | U    |      1 |      1 |      1 |00:00:00.01 |       2 |    
----------------------------------------------------------------------------------------------

select * from t
where  c2 = 1;

select * 
from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST'));

----------------------------------------------------------------------------------------------    
| Id  | Operation                   | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |    
----------------------------------------------------------------------------------------------    
|   0 | SELECT STATEMENT            |      |      1 |        |      1 |00:00:00.01 |       3 |    
|   1 |  TABLE ACCESS BY INDEX ROWID| T    |      1 |      1 |      1 |00:00:00.01 |       3 |    
|*  2 |   INDEX UNIQUE SCAN         | UI   |      1 |      1 |      1 |00:00:00.01 |       2 |    
----------------------------------------------------------------------------------------------

有一个例外。唯一约束可以是外键的目标。而唯一索引(单独)不能:

alter table t
  add constraint fk 
  foreign key ( c1 )
  references t ( c2 );
  
ORA-02270: no matching unique or primary key for this column-list
  
alter table t
  add constraint fk 
  foreign key ( c2 )
  references t ( c1 );

假设您创建了唯一和外键约束,这使优化器能够消除某些查询中的 table。这可以带来巨大的性能优势:

select t1.* from t t1
join   t t2
on     t1.c1 = t2.c2;

select * 
from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST'));

-------------------------------------------------------------------------------------    
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |    
-------------------------------------------------------------------------------------    
|   0 | SELECT STATEMENT   |      |      1 |        |   5000 |00:00:00.01 |     202 |    
|   1 |  NESTED LOOPS      |      |      1 |  10000 |   5000 |00:00:00.01 |     202 |    
|   2 |   TABLE ACCESS FULL| T    |      1 |  10000 |   5000 |00:00:00.01 |      60 |    
|*  3 |   INDEX UNIQUE SCAN| UI   |   5000 |      1 |   5000 |00:00:00.01 |     142 |    
------------------------------------------------------------------------------------- 

select t1.* from t t1
join   t t2
on     t1.c2 = t2.c1;

select * 
from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST'));

------------------------------------------------------------------------------------    
| Id  | Operation         | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |    
------------------------------------------------------------------------------------    
|   0 | SELECT STATEMENT  |      |      1 |        |   5000 |00:00:00.01 |      60 |    
|*  1 |  TABLE ACCESS FULL| T    |      1 |  10000 |   5000 |00:00:00.01 |      60 |    
------------------------------------------------------------------------------------  

Table stats 会影响优化器是否使用索引。如果您搜索小于 100 的唯一值:

select * from t
where  c1 <= 100;

如果 table 中只有 100 行,优化器更有可能进行完整的 table 扫描。但如果有数百万,索引就会变得更有吸引力。