目录sql
@session
在看《收获,不止SQL优化》一书,并根据书中例子进行实践,整理成笔记数据结构
Oracle索引分为BTree索引、位图索引、反向索引、函数索引、全文索引等等。oracle
Oracle索引中最经常使用的是BTree索引,因此就以BTree索引为例,讲一下BTree索引,BTree索引数据结构是一种二叉树的结构,索引由根块(Root)、茎块(Branch)、叶子块(Leaf)组成,其中叶子块主要存储索引列具体值(Key Column Value)以及能定位到数据块具体位置的Rowid,茎块和根块主要保存对应下级对应索引app
索引特性:ide
drop table t purge; create table t as select * from dba objects; update t set object_id=rownum ; commit; create index idx_id_type on t(object_id, object_type) ; create index idx_type_id on t(object_type , object_id) ; set autotrace off; alter session set statistics_level=all ; select /*+index(t idx_id_type)*/ * from t where object_id=20 and object_type='TABLE'; select * from table(dbms_xplan.display cursor(null , null , 'allstats last')); select /*+index(t,idx_type id)*/ * from t where object_id=20 and object_type= 'TABLE'; select * from table(dbms_xplan.display cursor(null , null , 'allstats last'));
select /*+index (t, idx_id_type)*/ * from t where object_id>=20 and object_id<2000 and object_type='TABLE'; select /*+index (t , idx_type_id) */ * from t where object_id>=20 and object_id<2000 and object type='TABLE';
set autotrace on select max(object_id) , min(object_id) from t;
笛卡尔乘积写法:函数
set autotrace on select max, min from (select max(object_id) max from t ) a , (select min(object_id) min from t ) b;
索引失效分为逻辑失效和物理失效性能
alter index index_name unusable;
索引分类:BTree索引、位图索引、函数索引、反向索引、全文索引测试
位图索引:位图索引储存的就是比特值优化
环境准备,位图索引性质适用于count时,效率最高
drop table t purge; create table t as select * from dba_objects; update t set object_id = rownum; commit;
不用索引的状况:
SQL> set autotrace on SQL> select count(*) from t; COUNT(*) ---------- 72016 执行计划 ---------------------------------------------------------- Plan hash value: 2966233522 ------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 288 (1)| 00:00:04 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | TABLE ACCESS FULL| T | 86565 | 288 (1)| 00:00:04 | ------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement (level=2) 统计信息 ---------------------------------------------------------- 4 recursive calls 0 db block gets 1111 consistent gets 0 physical reads 0 redo size 432 bytes sent via SQL*Net to client 419 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed SQL>
建立位图索引:
create bitmap index idx_bitm_t_status on t(status);
再次查询,走位图索引查询:
SQL> set autotrace on SQL> select count(*) from t; COUNT(*) ---------- 72016 执行计划 ---------------------------------------------------------- Plan hash value: 4272013625 -------------------------------------------------------------------------------- ----------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | -------------------------------------------------------------------------------- ----------- | 0 | SELECT STATEMENT | | 1 | 5 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | BITMAP CONVERSION COUNT | | 86565 | 5 (0)| 00:00:01 | | 3 | BITMAP INDEX FAST FULL SCAN| IDX_BITM_T_STATUS | | | | -------------------------------------------------------------------------------- ----------- Note ----- - dynamic sampling used for this statement (level=2) 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 6 consistent gets 0 physical reads 0 redo size 432 bytes sent via SQL*Net to client 419 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed SQL>
注意要点:
位图索引更新列容易形成死锁,因此查询比较多列才适合建位图索引,更新比较多的列就尽可能不要建索引
函数索引:就是将一个函数计算的结果存储在行的列中
环境准备:
drop table t purge; create table t (id int, status varchar2(2)); insert into t select 1,'N' from dual; insert into t select rownum ,'Y' from dual connect by rownum <1000; commit;
不走索引的查询:
SQL> set autotrace on SQL> select * from t where (case when status='N' then 'No' end)='No'; ID STAT ---------- ---- 1 N 执行计划 ---------------------------------------------------------- Plan hash value: 1601196873 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 16 | 3 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| T | 1 | 16 | 3 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(CASE "STATUS" WHEN 'N' THEN 'No' END ='No') Note ----- - dynamic sampling used for this statement (level=2) 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 8 consistent gets 0 physical reads 0 redo size 486 bytes sent via SQL*Net to client 419 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed SQL>
建立函数索引:
create index idx_status on t (case when status ='N' then 'No' end);
走函数索引的查询:
SQL> select * from t where (case when status='N' then 'No' end)='No'; ID STAT ---------- ---- 1 N 执行计划 ---------------------------------------------------------- Plan hash value: 3908194542 -------------------------------------------------------------------------------- ---------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------- ---------- | 0 | SELECT STATEMENT | | 10 | 200 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| T | 10 | 200 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | IDX_STATUS | 4 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------- ---------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access(CASE "STATUS" WHEN 'N' THEN 'No' END ='No') Note ----- - dynamic sampling used for this statement (level=2) 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 2 consistent gets 0 physical reads 0 redo size 486 bytes sent via SQL*Net to client 419 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed SQL>
注意要点:
自定义函数时要加上deterministic 关键字,否则不能创建函数索引
创建一个自定义函数:
create or replace function f_addusl(i int) return int is begin return(i + 1); end;
尝试创建函数索引:
create index idx_ljb_test on t(f_addusl(id));
提示:ORA-30553:函数不能肯定
用deterministic 关键字,就能够创建函数索引
create or replace function f_addusl(i int) return int deterministic is begin return(i + 1); end;
在自定义函数代码更新时,对应的函数索引也要重建,不然不能用到原来的函数索引
反向索引:反向索引其实也是BTree索引的一种特例,不过在列中字节会反转的(反向索引是为了不热快竞争,好比索引列中存储的列值是递增的,好比250101,250102,按照BTree索引的特性,通常是按照顺序存储在索引右边的,因此容易造成热快竞争,而反向索引能够避免这种状况,由于反向索引是这样存储的,好比101052,201052,这样列值就距离很远了,避免了热快竞争)
反向索引不能用到范围查询
SQL> set autotrace on SQL> select * from t where created=sysdate; 未选定行 执行计划 ---------------------------------------------------------- Plan hash value: 913247507 -------------------------------------------------------------------------------- --------------- | Id | Operation | Name | Rows | Bytes | Cost (%C PU)| Time | -------------------------------------------------------------------------------- --------------- | 0 | SELECT STATEMENT | | 12 | 2484 | 286 (0)| 00:00:04 | | 1 | TABLE ACCESS BY INDEX ROWID| T | 12 | 2484 | 286 (0)| 00:00:04 | |* 2 | INDEX RANGE SCAN | IDX_REV_CREATED | 346 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------- --------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("CREATED"=SYSDATE@!) Note ----- - dynamic sampling used for this statement (level=2) 统计信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 2 consistent gets 0 physical reads 0 redo size 1191 bytes sent via SQL*Net to client 408 bytes received via SQL*Net from client 1 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 0 rows processed SQL>
范围查询,发现不走反向索引查询
SQL> select * from t where created>= sysdate-10 and created <= sysdate-1; OWNER ------------------------------------------------------------ OBJECT_NAME -------------------------------------------------------------------------------- SUBOBJECT_NAME OBJECT_ID ------------------------------------------------------------ ---------- DATA_OBJECT_ID OBJECT_TYPE CREATED -------------- -------------------------------------- -------------- LAST_DDL_TIME TIMESTAMP STATUS TE GE SE -------------- -------------------------------------- -------------- -- -- -- NAMESPACE EDITION_NAME ---------- ------------------------------------------------------------ SYS ICOL$ 20 2 TABLE 15-6月 -19 02-4月 -10 2010-04-02:13:18:38 VALID N N N 1 SYS I_USER1 46 46 INDEX 14-6月 -19 OWNER ------------------------------------------------------------ OBJECT_NAME -------------------------------------------------------------------------------- SUBOBJECT_NAME OBJECT_ID ------------------------------------------------------------ ---------- DATA_OBJECT_ID OBJECT_TYPE CREATED -------------- -------------------------------------- -------------- LAST_DDL_TIME TIMESTAMP STATUS TE GE SE -------------- -------------------------------------- -------------- -- -- -- NAMESPACE EDITION_NAME ---------- ------------------------------------------------------------ 02-4月 -10 2010-04-02:13:18:38 VALID N N N 4 SYS CON$ 28 28 TABLE 13-6月 -19 02-4月 -10 2010-04-02:13:18:38 VALID N N N 1 SYS OWNER ------------------------------------------------------------ OBJECT_NAME -------------------------------------------------------------------------------- SUBOBJECT_NAME OBJECT_ID ------------------------------------------------------------ ---------- DATA_OBJECT_ID OBJECT_TYPE CREATED -------------- -------------------------------------- -------------- LAST_DDL_TIME TIMESTAMP STATUS TE GE SE -------------- -------------------------------------- -------------- -- -- -- NAMESPACE EDITION_NAME ---------- ------------------------------------------------------------ UNDO$ 15 15 TABLE 12-6月 -19 02-4月 -10 2010-04-02:13:18:38 VALID N N N 1 SYS C_COBJ# 29 29 CLUSTER 11-6月 -19 02-4月 -10 2010-04-02:13:18:38 VALID N N N OWNER ------------------------------------------------------------ OBJECT_NAME -------------------------------------------------------------------------------- SUBOBJECT_NAME OBJECT_ID ------------------------------------------------------------ ---------- DATA_OBJECT_ID OBJECT_TYPE CREATED -------------- -------------------------------------- -------------- LAST_DDL_TIME TIMESTAMP STATUS TE GE SE -------------- -------------------------------------- -------------- -- -- -- NAMESPACE EDITION_NAME ---------- ------------------------------------------------------------ 5 SYS I_OBJ# 3 3 INDEX 10-6月 -19 02-4月 -10 2010-04-02:13:18:38 VALID N N N 4 SYS PROXY_ROLE_DATA$ OWNER ------------------------------------------------------------ OBJECT_NAME -------------------------------------------------------------------------------- SUBOBJECT_NAME OBJECT_ID ------------------------------------------------------------ ---------- DATA_OBJECT_ID OBJECT_TYPE CREATED -------------- -------------------------------------- -------------- LAST_DDL_TIME TIMESTAMP STATUS TE GE SE -------------- -------------------------------------- -------------- -- -- -- NAMESPACE EDITION_NAME ---------- ------------------------------------------------------------ 25 25 TABLE 09-6月 -19 02-4月 -10 2010-04-02:13:18:38 VALID N N N 1 SYS I_IND1 41 41 INDEX 08-6月 -19 02-4月 -10 2010-04-02:13:18:38 VALID N N N 4 OWNER ------------------------------------------------------------ OBJECT_NAME -------------------------------------------------------------------------------- SUBOBJECT_NAME OBJECT_ID ------------------------------------------------------------ ---------- DATA_OBJECT_ID OBJECT_TYPE CREATED -------------- -------------------------------------- -------------- LAST_DDL_TIME TIMESTAMP STATUS TE GE SE -------------- -------------------------------------- -------------- -- -- -- NAMESPACE EDITION_NAME ---------- ------------------------------------------------------------ SYS I_CDEF2 54 54 INDEX 07-6月 -19 02-4月 -10 2010-04-02:13:18:38 VALID N N N 4 已选择9行。 执行计划 ---------------------------------------------------------- Plan hash value: 1322348184 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 12 | 2484 | 292 (2)| 00:00:04 | |* 1 | FILTER | | | | | | |* 2 | TABLE ACCESS FULL| T | 12 | 2484 | 292 (2)| 00:00:04 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(SYSDATE@!-10<=SYSDATE@!-1) 2 - filter("CREATED">=SYSDATE@!-10 AND "CREATED"<=SYSDATE@!-1) Note ----- - dynamic sampling used for this statement (level=2) 统计信息 ---------------------------------------------------------- 5 recursive calls 0 db block gets 1112 consistent gets 0 physical reads 0 redo size 1770 bytes sent via SQL*Net to client 419 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 9 rows processed SQL>
全文索引:所谓Oracle全文索引是经过Oracle词法分析器(lexer)将全部的表意单元term存储dr$开头的表里并存储term出现的位置、次数、hash值等等信息,Oracle提供了basic_lexer(针对英语)、chinese_vgram_lexer(汉语分析器)、chinese_lexer(新的汉语分析器)。
Oracle的全文索引具体能够采用通配符查找、模糊匹配、相关分类、近似查找、条件加权和词意扩充等方法
环境准备
drop table t purge; create table t as select * from dba_objects where object_name is not null; update t set object_name ='高兴' where rownum<=2; commit; select * from t where object_name like '%高兴%';
设置词法分析器
//设置词法分析器 BEGIN ctx_ddl.create_preference ('lexer1', 'chinese_vgram_lexer'); END;
解锁ctxsys用户,同时给你的测试帐号(我这里用scott)受权使用ctx_ddl
//解锁ctxsys用户同时受权 grant ctxapp to scott; alter user ctxsys account unlock; alter user ctxsys identified by ctxsys; connect ctxsys/ctxsys; grant execute on ctx_ddl to scott; connect scott/11;
创建全文索引
//删除全文索引 drop index idx_content; //查看数据文件信息 select * from v$datafile; //创建全文索引 CREATE INDEX idx_content ON t(object_name) indextype is ctxsys.context parameters('lexer lexer1');
注意要点:更新数据时候记得执行全文索引同步命令,不然将看不到更新数据
exec ctx_ddl.sync_index('idx_content','20M');