Oracle Index 和null 研究
阿新 • • 發佈:2019-02-18
Indexing null values
安裝關係資料庫理論, null表示未知,Oracle b-tree index是不包含null的。考慮如下表:
create table tt (t_id number, t_name varchar2(10));
create index tt_idx on tt(t_name);
select * from tt where t_name is null是不會使用index scan的,這經常會造成效能問題。
解決辦法就是:建立一個函式索引,並在select 中包含該函式,如:
create index tt_idex on tt( nvl(t_name), 1); select * from tt where nvl(t_name,1)=1;
從11g開始有另一個方法:
create index tt_idx on tt(t_name asc, 1);
這裡1可以是任意數字或字母。而這時,select語句的謂詞不需要更改,還是t_name is null.Uniqueness and null
drop index tt_idx;
create unique index tt_idx on tt(t_name);
insert into tt values(1, null);
commit;
insert into tt values(1, null);
commit;
這段SQL可以執行成功。這是因為null不被索引包含。
第二個事務會失敗。因為null不被索引包含, 兩個'1'就是重複值!create table ttt2 (tt2_id number, tt21 varchar2(10), tt22 varchar2(10)); create unique index ttt2_idx on ttt2(tt21, tt22); --Successful insert into ttt2 values(1, null, null); insert into ttt2 values(1, null, null); commit; --Fail insert into ttt2 values(1, '1', null); insert into ttt2 values(1, '1', null); commit;
Conditional uniqueness
假如有需求:
- tt21, tt22都可以為null
- 僅在tt21和tt22都不為null時,需要保證唯一性!
這時的解決方法:Function based index 。
create table ttt2 (tt2_id number, tt21 varchar2(10), tt22 varchar2(10)); create or replace function conditional_uniqueness(p_tt21 varchar2, p_tt22 varchar2) return varchar2 DETERMINISTIC as begin if(p_tt21 is not null and p_tt22 is not null) then return p_tt21||p_tt22; else return null; end if; end; create unique index ttt2_idx on ttt2(conditional_uniqueness(tt21, tt22)); --Fail! insert into ttt2 values(1, '1','1'); insert into ttt2 values(1, '1','1'); --Successful insert into ttt2 values(1, '1',null); insert into ttt2 values(1, '1',null); --Successful insert into ttt2 values(1, null,'1'); insert into ttt2 values(1, null,'1'); commit;