【问题标题】:Unique index performance with or without unique column具有或不具有唯一列的唯一索引性能
【发布时间】:2021-01-10 09:41:02
【问题描述】:

当唯一索​​引列对相关列也有唯一约束时,性能有什么不同吗?

我知道唯一索引和非唯一索引在性能上是有区别的。

但我的问题是,如果列同时具有唯一约束和唯一索引,并且只有唯一索引而没有唯一约束,那么性能会有什么不同吗?

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

【问题讨论】:

  • 唯一索引!=唯一约束。虽然它们有一些相似之处,例如后者有时可能会创建前者,它们用于不同的事情。这里更大的问题是,你需要两者吗?

标签: oracle oracle11g sqlperformance sql-tuning


【解决方案1】:

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

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

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 );

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

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 |    
------------------------------------------------------------------------------------  

表统计信息会影响优化器是否使用索引。如果您搜索小于 100 的唯一值:

select * from t
where  c1 <= 100;

如果表中只有 100 行,优化器更有可能进行全表扫描。但如果有数百万,该指数就会变得更具吸引力。

【讨论】:

    猜你喜欢
    • 2021-11-18
    • 2013-01-05
    • 1970-01-01
    • 2015-01-17
    • 2020-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-22
    相关资源
    最近更新 更多