首页 > 数据库 > Oracle > 029.笔记:基本的索引原理-索引的类型
1.B树索引
1.1
B树索引是树形结构,包括树根块(root block)、树枝块(branch block)、叶块(leaf block)。
branch block中,树枝行包含链中下一个叶块的ID号。
leaf block包含了索引值、ROWID,以及指向前一个和后一个树叶块的指针。Oracle可以从两个方向遍历这个树。
Oracle不会对索引列上包含null值的行进行索引。如果索引是多个列的组合索引,而其中列上包含NULL值,这一行就会处于包含NULL值的索引列中,且将被处理为空(视为NULL)。
【技巧】索引列的值都存储在索引中。因此,可以建立一个组合索引,这些索引可以直接满足查询,而不用访问表。这就不用从表中检索数据,从而减少了I/O量。
1.2B-树索引的内部结构
我们可以使用如下方式将B树索引转储成树状结构的形式而呈现出来:
alter session set events 'immediate trace name treedump level INDEX_OBJECT_ID';
--转储整个索引树形结构
select object_id from user_objects where object_name='INDEX5';
alter session set events 'immediate trace name treedump level 52895';
../udump/ls -ltr
--转储单个块
select dbms_utility.data_block_address_file(25225994),dbms_utility.data_block_address_block(25225994) from dual;--25225994是上个转储文件第三列的值
alter system dump datafile 6 block 60170;
--详见附件:附:Oracle 索引结构、内部管理 - 光 仔 - 博客园.htm
附:Leonarding
场合:非常适合数据重复度低的字段 例如 身份证号码 手机号码 QQ号等字段,常用于主键 唯一约束,一般在在线交易的项目中用到的多些。
原理:一个键值对应一行(rowid) 格式: 【索引头|键值|rowid】
优点:当没有索引的时候,oracle只能全表扫描where qq=40354446 这个条件那么这样是灰常灰常耗时的,当数据量很大的时候简直会让人崩溃,那么有个B-tree索引我们就像翻书目录一样,直接定位rowid立刻就找到了我们想要的数据,实质减少了I/O操作就提高速度,它有一个显著特点查询性能与表中数据量无关,例如 查2万行的数据用了3 consistent get,当查询1200万行的数据时才用了4 consistent gets。
当我们的字段中使用了主键or唯一约束时,不用想直接可以用B-tree索引
缺点:不适合键值重复率较高的字段上使用,例如 第一章 1-500page 第二章 501-1000page
附:光 仔
B树索引是一个典型的树结构,其包含的组件主要是:
1) 叶子节点(Leaf node):包含条目直接指向表里的数据行。
2) 分支节点(Branch node):包含的条目指向索引里其他的分支节点或者是叶子节点。
3) 根节点(Root node):一个B树索引只有一个根节点,它实际就是位于树的最顶端的分支节点。
1.3 B树索引的访问
附:光仔
我们已经知道了B树索引的体系结构,那么当oracle需要访问索引里的某个索引条目时,oracle是如何找
到该索引条目所在的数据块的呢?
当oracle进程需要访问数据文件里的数据块时,oracle会有两种类型的I/O操作方式:
1) 随机访问,每次读取一个数据块(通过等待事件“db file sequential read”体现出来)。
2) 顺序访问,每次读取多个数据块(通过等待事件“db file scattered read”体现出来)。
第一种方式则是访问索引里的数据块,而第二种方式的I/O操作属于全表扫描。这里顺带有一个问题,为
何随机访问会对应到db file sequential read等待事件,而顺序访问则会对应到db file scattered read等待事件呢?这似乎反过来了,随机访问才应该是分散(scattered)的,而顺序访问才应该是顺序(sequential)的。其实,等待事件主要根据实际获取物理I/O块的方式来命名的,而不是根据其在I/O子系统的逻辑方式来命名的。下面对于如何获取索引数据块的方式中会对此进行说明。
我们看到前面对B树索引的体系结构的描述,可以知道其为一个树状的立体结构。其对应到数据文件里的
排列当然还是一个平面的形式,也就是像下面这样。因此,当oracle需要访问某个索引块的时候,势必会在这个结构上跳跃的移动。
/根/分支/分支/叶子/…/叶子/分支/叶子/叶子/…/叶子/分支/叶子/叶子/…/叶子/分支/.....
当oracle需要获得一个索引块时,首先从根节点开始,根据所要查找的键值,从而知道其所在的下一层的分支节点,然后访问下一层的分支节点,再次同样根据键值访问再下一层的分支节点,如此这般,最终访问到最底层的叶子节点。可以看出,其获得物理I/O块时,是一个接着一个,按照顺序,串行进行的。在获得最终物理块的过程中,我们不能同时读取多个块,因为我们在没有获得当前块的时候是不知道接下来应该访问哪个块的。因此,在索引上访问数据块时,会对应到db file sequential read等待事件,其根源在于我们是按照顺序从一个索引块跳到另一个索引块,从而找到最终的索引块的。
那么对于全表扫描来说,则不存在访问下一个块之前需要先访问上一个块的情况。全表扫描时,oracle知道要访问所有的数据块,因此唯一的问题就是尽可能高效的访问这些数据块。因此,这时oracle可以采用同步的方式,分几批,同时获取多个数据块。这几批的数据块在物理上可能是分散在表里的,因此其对应到db file scattered read等待事件。
2.位图索引
位图索引非常适合决策支持系统和数据仓库。
对于有较低基数的列需要使用位图索引。
create bitmap index dept_idx2 on dept(deptno);
【技巧】在一个查询中合并多个位图索引后,可以使性能显著提高。位图索引使用固定长度的数据类型要比可变长度的数据类型好。
较大尺寸的块也会提高对位图索引的存储和读取性能。
【位图索引的限制】
基于规则的优化器不会考虑位图索引
当执行ALTER TABLE语句并修改包含有位图索引的列时,会使位图索引失效。
位图索引不包含任何列数据,并且不能用于任何类型的完整性检查。
位图索引不能被声明为唯一索引。
位图索引的最大长度为30。
【实验】比较位图索引与B树组合索引
第一步:
dept表加三个列:SEX、city、xl
第二步:制作数据
update dept
set sex=(case when mod(rownum,2)=0 then '男' else '女' end )
,city=to_char(mod(rownum,10) )||'号城市'
,xl= to_char(mod(rownum,6) )||'级别学历';
commit;
第三步:创建B树索引
3.1 B树组合索引
create index btree_idx1 on dept(city,xl,sex);
3.2 位图索引
create bitmap index bit_idx_sex on dept(sex);
create bitmap index bit_idx_city on dept(city);
create bitmap index bit_idx_xl on dept(xl);
第四步:比较索引占用的空间
select t.INDEX_NAME,t.index_type,t.LEAF_BLOCKS
from user_indexes t where t.TABLE_NAME='DEPT';
-----------------------------------------
INDEX_NAME INDEX_TYPE LEAF_BLOCKS
1 BTREE_IDX1 NORMAL 193
2 BIT_IDX_SEX BITMAP 2
3 BIT_IDX_CITY BITMAP 10
4 BIT_IDX_XL BITMAP 6
-----------------------------------------
第五步:效率比较
5.1准备
begin
dbms_stats.gather_table_stats(ownname => 'scott',tabname => 'dept');
end;
set autotrace traceonly exp stat;
5.2位图索引
SQL> select /*+index(t BIT_IDX_CITY)*/* from scott.dept t where t.sex='男' and city='8号城市' and xl='2级别学历';
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 1743288326
--------------------------------------------------------------------------------
-------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU
)| Time |
--------------------------------------------------------------------------------
-------------
| 0 | SELECT STATEMENT | | 1 | 37 | 2 (0
)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID | DEPT | 1 | 37 | 2 (0
)| 00:00:01 |
| 2 | BITMAP CONVERSION TO ROWIDS| | | |
| |
| 3 | BITMAP AND | | | |
| |
|* 4 | BITMAP INDEX SINGLE VALUE| BIT_IDX_SEX | | |
| |
|* 5 | BITMAP INDEX SINGLE VALUE| BIT_IDX_CITY | | |
| |
--------------------------------------------------------------------------------
-------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("XL"='2????????')
4 - access("T"."SEX"='??')
5 - access("CITY"='8??????')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
542 bytes sent via SQL*Net to client
374 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
5.3B树索引
SQL> select /*+index(t BTREE_IDX1)*/* from scott.dept t where t.sex='男' and city='8号城市' and xl='2级别学历';
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 1083075104
--------------------------------------------------------------------------------
----------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
Time |
--------------------------------------------------------------------------------
----------
| 0 | SELECT STATEMENT | | 1 | 37 | 167 (0)|
00:00:03 |
| 1 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 37 | 167 (0)|
00:00:03 |
|* 2 | INDEX RANGE SCAN | BTREE_IDX1 | 1437 | | 7 (0)|
00:00:01 |
--------------------------------------------------------------------------------
----------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("CITY"='8??????' AND "XL"='2????????' AND "T"."SEX"='??')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
542 bytes sent via SQL*Net to client
374 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
【小结】1.多个位图索引连合使用的效率比B树索引的效率高;
2.二者的consistent gets一样。但是,位图COST仅为2,组合索引为167。
附:Leonarding
位图索引场合:列的基数很少,可枚举,重复值很多,数据不会被经常更新
原理:一个键值对应很多行(rowid), 格式:键值 start_rowid end_rowid 位图
优点:OLAP 例如报表类数据库 重复率高的数据 特定类型的查询例如count、or、and等逻辑操作因为只需要进行位运算即可得到我们需要的结果
缺点:不适合重复率低的字段,还有经常DML操作(insert,update,delete),因为位图索引的锁代价极高,修改一个位图索引段影响整个位图段,例如修改
一个键值,会影响同键值的多行,所以对于OLTP 系统位图索引基本上是不适用的
3.位图连接索引
位图连接索引是基于两个表的连接的位图索引,在数据仓库环境中使用这种索引改进连接维度表和事实表的查询的性能。创建位图连接索引时,标准方法是
连接索引中常用的维度表和事实表。
【位图连接索引的限制】
只可以索引维度表中的列。
用于连接的列必须是维度表中的主键或唯一约束;如果是复合主键,则必须使用连接中的每一列。
不可以对索引组织表创建位图连接索引,并且适用于常规位图索引的限制也适用于位图连接索引。
注意:位图连接索引只可以索引维度表中的列,否则效率反而会下降。见下面的实验
【位图连接索引效率】
--0.准备
--创建维度表
create table dim_city
(city varchar2(10),
city_name varchar2(20)
);
insert into dim_city
select distinct city,city||'name' from dept;
commit;
alter table DIM_CITY add constraint pry_city_name primary key (CITY);
--创建维
create dimension dim_city_dim
level lcity is(dim_city.city)
level lcity_name is(dim_city.city_name)
attribute lcity determines (dim_city.city,dim_city.city_name);
CREATE DIMENSION products_dim
LEVEL product IS (products.prod_id)
LEVEL subcategory IS (products.prod_subcategory)
LEVEL category IS (products.prod_category)
HIERARCHY prod_rollup (
product CHILD OF
subcategory CHILD OF
category
)
ATTRIBUTE product_info LEVEL product DETERMINES
(products.prod_name, products.prod_desc,
prod_weight_class, prod_unit_of_measure,
prod_pack_size, prod_status, prod_list_price, prod_min_price)
ATTRIBUTE subcategory DETERMINES
(prod_subcategory, prod_subcategory_desc)
ATTRIBUTE category DETERMINES
(prod_category, prod_category_desc);
--创建索引
create bitmap index bit_dimcity
on dept(dim_city.city_name)
from dept,dim_city
where dept.city=dim_city.city;
--1.使用位图连接索引
SQL> select /*+index(t BIT_DIMCITY) */count(*),city_name
2 from scott.dept t
3 inner join scott.dim_city d on(d.city=t.city)
4 group by d.city_name;
10 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1438362396
--------------------------------------------------------------------------------
--------------
| Id | Operation | Name | Rows | Bytes | Cost (%CP
U)| Time |
--------------------------------------------------------------------------------
--------------
| 0 | SELECT STATEMENT | | 43105 | 1136K| 1831 (
1)| 00:00:22 |
| 1 | HASH GROUP BY | | 43105 | 1136K| 1831 (
1)| 00:00:22 |
|* 2 | HASH JOIN | | 43105 | 1136K| 1826 (
1)| 00:00:22 |
| 3 | TABLE ACCESS FULL | DIM_CITY | 10 | 190 | 3 (
0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID | DEPT | 43105 | 336K| 1822 (
1)| 00:00:22 |
| 5 | BITMAP CONVERSION TO ROWIDS| | | |
| |
| 6 | BITMAP INDEX FULL SCAN | BIT_DIMCITY | | |
| |
--------------------------------------------------------------------------------
--------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("D"."CITY"="T"."CITY")
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
5 recursive calls
0 db block gets
49134 consistent gets
12 physical reads
0 redo size
691 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
10 rows processed
--2.使用普通的位图索引
SQL> select /*+indexa(t BIT_DIMCITY) */count(*),city_name
2 from scott.dept t
3 inner join scott.dim_city d on(d.city=t.city)
4 group by d.city_name;
10 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2202493398
--------------------------------------------------------------------------------
--------------
| Id | Operation | Name | Rows | Bytes | Cost (%CP
U)| Time |
--------------------------------------------------------------------------------
--------------
| 0 | SELECT STATEMENT | | 43105 | 1136K| 18 (2
8)| 00:00:01 |
| 1 | HASH GROUP BY | | 43105 | 1136K| 18 (2
8)| 00:00:01 |
| 2 | NESTED LOOPS | | 43105 | 1136K| 13 (
0)| 00:00:01 |
| 3 | TABLE ACCESS FULL | DIM_CITY | 10 | 190 | 3 (
0)| 00:00:01 |
| 4 | BITMAP CONVERSION TO ROWIDS| | 4311 | 34488 | 13 (
0)| 00:00:01 |
|* 5 | BITMAP INDEX SINGLE VALUE | BIT_IDX_CITY | | |
| |
--------------------------------------------------------------------------------
--------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("D"."CITY"="T"."CITY")
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
4 recursive calls
0 db block gets
37 consistent gets
12 physical reads
0 redo size
691 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
10 rows processed
4.HASH索引
使用HASH索引必须要使用HASH集群。建立一个集群或HASH集群的同时,也就定义了一个集群键。这个键告诉Oracle如何在集群上存储表。在存储数据时,所有与
这个集群键相关的行都被存储在一个数据库块上。如果数据都存储在同一个数据库块上,并且将HASH索引作为WHERE子句中的确切匹配,Oracle就可以通过执行一个HASH函数
和I/O来访问数据----而通过使用一个二元高度为4的B树索引来访问数据库,则需要在检索数据时使用4个I/O。
HASH索引可能是访问数据库中数据的最快方法,但它也有自身的缺点:
1)集群键上不同值的数目必须在创建HASH集群之前就要知道。需要在创建HASH集群的时候指定这个值。低估了集群键的不同值的数字可能会造成冲突。
2)高估了集群键的值还可能浪费空间
3)如果应用程序经常在集群表上进行全表扫描,HASH集群可能也不是最好的选择。
通常,HASH对于一些包含有序值的静态数据非常有效
create cluster staff_clust2(sno number) hashkeys 10000;--在段中产生10240个块,平均1个HASHKEY=1个块
create table staff2(
sno number,
sname varchar2(20),
constraint staff2_pk primary key(sno)
)
cluster staff_clust (sno);
DECLARE
i NUMBER;
BEGIN
FOR i in 1..5000 loop
insert into staff2 values(i,to_char(i)||'a ...b');
end loop;
commit;
END;
--散列群集(hash cluster)也可以用于反规格化表,但是在许多情况下,散列群集用于单一的表。
--如果使用基于主键的等式,那么散列群集可以提供最快的数据检索。范围搜索是非常不利的。
【实验】与B树索引比较效率
--1)创建B树索引的表
create table staff(
sno number,
sname varchar2(20),
constraint staff_pk primary key(sno)
);
DECLARE
i NUMBER;
BEGIN
FOR i in 1..5000 loop
insert into staff values(i,to_char(i)||'a ...b');
end loop;
commit;
END;
--2)
begin
dbms_stats.gather_table_stats(ownname => 'scott',tabname => 'staff2');
dbms_stats.gather_table_stats(ownname => 'scott',tabname => 'staff');
end;
--3) HASH索引
SQL> select * from scott.staff2 t where t.sno=4222;
SNO SNAME
---------- --------------------
4222 4222a ...b
Execution Plan
----------------------------------------------------------
Plan hash value: 3460466525
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 14 | 1 (0)| 00:00:01 |
|* 1 | TABLE ACCESS HASH| STAFF2 | 1 | 14 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T"."SNO"=4222)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
1 consistent gets
0 physical reads
0 redo size
473 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
--4)B树索引
SQL> select * from scott.staff t where t.sno=4222;
SNO SNAME
---------- --------------------
4222 4222a ...b
Execution Plan
----------------------------------------------------------
Plan hash value: 2288633111
--------------------------------------------------------------------------------
--------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Ti
me |
--------------------------------------------------------------------------------
--------
| 0 | SELECT STATEMENT | | 1 | 14 | 2 (0)| 00
:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| STAFF | 1 | 14 | 2 (0)| 00
:00:01 |
|* 2 | INDEX UNIQUE SCAN | STAFF_PK | 1 | | 1 (0)| 00
:00:01 |
--------------------------------------------------------------------------------
--------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T"."SNO"=4222)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
381 bytes sent via SQL*Net to client
374 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
【实验小结】
1)HASH索引:COST=1,consistent get=1
2)B树索引: COST=2,consistent get=3
3)试分析:B树索引在索引树上进行了两次I/O(一次在根结点(最顶端的树枝结点),一次在树叶结点),对表进行了一次I/O。
5.索引组织表
IOT存在下列限制:
(1)必须有一个主键约束
(2)IOT不能是群集表
(3)不能对IOT应用复合分区
(4)IOT中不能定义类型为LONG的列
5.1 创建表
create table tb_objects
(
OBJECT_NAME VARCHAR2(128),
SUBOBJECT_NAME VARCHAR2(30) ,
OBJECT_ID NUMBER ,
DATA_OBJECT_ID NUMBER ,
OBJECT_TYPE VARCHAR2(19) ,
CREATED DATE ,
LAST_DDL_TIME DATE ,
TIMESTAMP VARCHAR2(19) ,
STATUS VARCHAR2(7) ,
TEMPORARY VARCHAR2(1) ,
GENERATED VARCHAR2(1) ,
SECONDARY VARCHAR2(1),
constraint obj_pk primary key(object_id)
)
organization index
including object_name tablespace ts1
overflow tablespace ts_over;
如果您的表经常需要按主键进行排序,那么可以最大限度地快速获得查询的返回结果。在这种情况下,Oracle会忽略排序操作。
IOT可以像堆组织表一样进行分区。
create table woodscrew_orders (
ord_id number not null,
ord_date date,
cust_id number not null,
scr_id number not null,
ord_cnt number,
warehouse_id number not null,
region varchar2(20),
constraint pk_wdscr_orders primary key (ord_id,ord_date))
organization index
including ord_date pctthreshold 20
overflow tablespace wd_scr_overflow
partition by range (ord_date) ...
;
【技巧】对于总是通过对主键的精确匹配或范围扫描进行访问的表,就需要考虑使用索引组织表。
可以在索引组织表上建立二级索引。
6.反转键索引
反转键索引,如果数据以反转键索引存储,这些数据的值就会与原先存储的数值相反。这样,数据1234,1235,1236就会被存储成4321,5321,6321。结果
就是索引会为每次新插入的行更新不同的索引块。
注:反转键索引可以使相邻的索引存储在不同的块中,以减少索引块的争用。
【技巧】如果磁盘容量有限,同时还要执行大量的有序载入,就可以使用反转键索引。
不可以将反转键索引与位图索引或索引组织表结合使用。
7.基于函数的索引
7.1创建基于函数的索引要考虑的问题:
1)能限制在这个列上使用的函数吗?如果能,能限制所有在这个列上执行的所有函数吗?
2)是否有足够应付额外索引的存储空间?
3)在每列上增加的索引数量会对针对该表执行的DML语句的性能带来何种影响?
7.2注意
对于优化器所使用的基于函数的索引来说,必须把初始参数QUERY_REWRITE_ENABLED设定为TRUE。
alter system set QUERY_REWRITE_ENABLED=true;--查询重写,物化视图能用到
7.3【实验】
1)未使用函数索引
SELECT count(*)
FROM SCOTT.DEPT T
WHERE round(deptno+0.11,1)/2 > 5000
--COST 88
2)创建函数索引
create index idx_f_com on dept(round(deptno+0.11,1)/2);
3)使用函数索引
SELECT count(*)
FROM SCOTT.DEPT T
WHERE round(deptno+0.11,1)/2 > 5000
--COST 2
8.分区索引
B树和位图索引都可以被分区,而HASH索引不可以被分区。可以有好几种分区方法:表被分区而索引未被分区;表未被分区而索引被分区;表和索引都被分区。
8.1本地分区索引
1.本地索引一定是分区索引,分区键等同于表的分区键,分区数等同于表的分区说,一句话,本地索引的分区机制和表的分区机制一样。
2.如果本地索引的索引列以分区键开头,则称为前缀局部索引。
3.如果本地索引的列不是以分区键开头,或者不包含分区键列,则称为非前缀索引。
4.前缀和非前缀索引都可以支持索引分区消除,前提是查询的条件中包含索引分区键。
5.本地索引只支持分区内的唯一性,无法支持表上的唯一性,因此如果要用本地索引去给表做唯一性约束,则约束中必须要包括分区键列。
6.本地分区索引是对单个分区的,每个分区索引只指向一个表分区,全局索引则不然,一个分区索引能指向n个表分区,同时,一个表分区,也可能指向n个索引分区,对分区表中的某个分区做truncate或者move,shrink等,可能会影响到n个全局索引分区,正因为这点,本地分区索引具有更高的可用性。
7.位图索引只能为本地分区索引。
8.本地索引多应用于数据仓库环境中。本地索引:创建了一个分区表后,如果需要在表上面创建索引,并且索引的分区机制和表的分区机制一样,那么这样的索引就叫做本地分区索引。
本地索引是由ORACLE自动管理的,它分为有前缀的本地索引和无前缀的本地索引。
什么叫有前缀的本地索引?有前缀的本地索引就是包含了分区键,并且将其作为引导列的索引。
什么叫无前缀的本地索引?无前缀的本地索引就是没有将分区键的前导列作为索引的前导列的索引。下面举例说明:
create table test (id number,data varchar2(100))
partition by RANGE (id)
(
partition p1 values less than (1000) tablespace p1,
partition p2 values less than (2000) tablespace p2,
partition p3 values less than (maxvalue) tablespace p3
);
create index i_id on test(id) local; 因为id是分区键,所以这样就创建了一个有前缀的本地索引。
8.2全局分区索引
1.全局索引的分区键和分区数和表的分区键和分区数可能都不相同,表和全局索引的分区机制不一样。
2.全局索引可以分区,也可以是不分区索引,全局索引必须是前缀索引,即全局索引的索引列必须是以索引分区键作为其前几列。
3.全局分区索引的索引条目可能指向若干个分区,因此,对于全局分区索引,即使只截断一个分区中的数据,都需要rebulid若干个分区甚至是整个索引。
4.全局索引多应用于oltp系统中。
5.全局分区索引只按范围或者散列hash分区,hash分区是10g以后才支持。
6.oracle9i以后对分区表做move或者truncate的时可以用update global indexes语句来同步更新全局分区索引,用消耗一定资源来换取高度的可用性。
7.表用a列作分区,索引用b做局部分区索引,若where条件中用b来查询,那么oracle会扫描所有的表和索引的分区,成本会比分区更高,此时可以考虑用b做全局分区索引。
全局索引:与本地分区索引不同的是,全局分区索引的分区机制与表的分区机制不一样。全局分区索引全局分区索引只能是B树索引,到目前为止(10gR2),oracle只支持有前缀的全局索引。另外oracle不会自动的维护全局分区索引,当我们在对表的分区做修改之后,如果执行修改的语句不加上update global indexes的话,那么索引将不可用。以上面创建的分区表test为例,讲解全局分区索引:
SQL> drop index i_id ;
Index dropped
SQL> create index i_id_global on test(id) global
2 partition by range(id)
3 ( partition p1 values less than (2000) tablespace p1,
4 partition p2 values less than (maxvalue) tablespace p2
5 );
9.快速重建索引
alter index cust_idx1 rebuild [partition p1] [online] parallel
tablespace cust_tblspc1
storage (pctincrease 0);
10.全文索引
附:leonarding
全文索引 Text index
定义:全文索引就是通过将文字按照某种语言进行词汇拆分,重新将数据组合存储,来达到快速检索的目的
场合:当字段里存储的都是文本时适合用全文索引,常用于搜索文字
优点:全文索引不是按照键值存储的,而是按照分词重组数据,常用于模糊查询Where name like '%leonarding%'效率比全表扫描高很多,适用OLAP系统,
OLTP系统里面用到的并不多。
缺点:全文索引会占用大量空间有时比原表本身占的空间还多,bug较多,维护困难。
实验:全文索引性能优势
创建一个表包含2个字段
LS@LEO> create table leo_text_t1 (id int,name varchar(10));
Table created.
在name字段上创建B-tree索引,但检索的时候并没有用,还是全表扫描
LS@LEO> create index leo_text_t1_bt_index on leo_text_t1(name);
Index created.
插入4条记录
insert into leo_text_t1 values(1,'Tom');
insert into leo_text_t1 values(2,'Tom Tom');
insert into leo_text_t1 values(1,'Tom');
insert into leo_text_t1 values(2,'Tom Tom');
commit;
LS@LEO> select * from leo_text_t1;
ID NAME
---------- ----------
1 Tom
2 Tom Tom
1 Tom
2 Tom Tom
我们在创建一个表,并在name字段上创建全文索引
create table leo_text_t2 as select * from leo_text_t1;
创建全文索引的前提
ORACLE10g 创建全文索引过程:
1,首先查看ORACLE是否已安装“全文检索工具”
通过查看是否存在 CTXSYS 用户,CTXAPP角色即可判断。
LS@LEO> select username from dba_users;
USERNAME
------------------------------
LS
CTXSYS 默认是没有的,需要安装2个脚本catctx.sql,drdefus.sql
2,如果ORACLE没有安装“全文检索工具”,则使用以下步骤手工安装。
a)进入ORACLE安装目录
cd $ORACLE_HOME
b)使用 DBA 角色登陆数据库
sqlplus sys/sys as sysdba
c)查看表空间文件存放路径
select name from v$datafile;
d)为 CTXSYS 用户创建表空间
CREATE TABLESPACE ctxsys
LOGGING
DATAFILE '/u01/app/oracle/oradata/LEO/file1/ctxsys01.dbf'
SIZE 32m
AUTOEXTEND ON
NEXT 32m MAXSIZE 2048m
EXTENT MANAGEMENT LOCAL ;
e)创建 CTXSYS 用户,创建 CTXAPP 角色
@?/ctx/admin/catctx.sql ctxsys ctxsys temp1 nolock
--(密码、表空间、临时表空间、用户状态)
--如果当前sql脚本无执行权限,请手工添加。
f)为 CTXSYS 执行初始化工作,如果没有此操作,后续操作会失败。
connect ctxsys/ctxsys;
@?/ctx/admin/defaults/drdefus.sql
3,创建全文索引
a)创建词法分析器及相关表
--词法分析器
execute ctx_ddl.create_preference('offerProdAddrLexer','CHINESE_LEXER');
--词法
execute ctx_ddl.create_preference('offerProdAddrList', 'BASIC_WORDLIST');
execute ctx_ddl.set_attribute('offerProdAddrList','PREFIX_INDEX','TRUE');
execute ctx_ddl.set_attribute('offerProdAddrList','PREFIX_MIN_LENGTH',1);
execute ctx_ddl.set_attribute('offerProdAddrList','PREFIX_MAX_LENGTH', 5);
execute ctx_ddl.set_attribute('offerProdAddrList','SUBSTRING_INDEX', 'YES');
b)创建全文索引
LS@LEO> conn ctxsys/ctxsys
Connected.
CTXSYS@LEO> create index ls.leo_text_t2_text_index on ls.leo_text_t2(name) indextype is ctxsys.context;
CTXSYS@LEO> conn ls/ls
Connected.
LS@LEO> set autotrace on;
LS@LEO> select * from leo_text_t1 where name like '%Tom%';
ID NAME
---------- ----------
1 Tom
2 Tom Tom
1 Tom
2 Tom Tom
Execution Plan 执行计划
----------------------------------------------------------
Plan hash value: 3687902158
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 80 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| LEO_TEXT_T1 | 4 | 80 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------------
全表扫描,cpu使用率3%
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("NAME" LIKE '%Tom%')
Note
-----
- dynamic sampling used for this statement动态采样
Statistics 统计信息
----------------------------------------------------------
56 recursive calls
0 db block gets
23 consistent gets 全表扫描没有使用B-tree索引,导致23次一致性读
0 physical reads
0 redo size
538 bytes sent via SQL*Net to client
381 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
4 rows processed
LS@LEO> select * from leo_text_t2 where contains(name,'Tom')>0;
ID NAME
---------- ----------
1 Tom
2 Tom Tom
1 Tom
2 Tom Tom
Execution Plan 执行计划
----------------------------------------------------------
Plan hash value: 2789465217
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 32 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| LEO_TEXT_T2 | 1 | 32 | 4 (0)| 00:00:01 |
|* 2 | DOMAIN INDEX | LEO_TEXT_T2_TEXT_INDEX | | | 4 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("CTXSYS"."CONTAINS"("NAME",'Tom')>0)
Note
-----
- dynamic sampling used for this statement动态采样
Statistics 统计信息
----------------------------------------------------------
11 recursive calls
0 db block gets
19 consistent gets
0 physical reads
0 redo size
545 bytes sent via SQL*Net to client
381 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4 rows processed
小结:从如上实验来看,当我们检索大量文字的时候使用全文索引要比全表扫描快很多了,有弊就有利,由于全文索引会占用大量空间提前预估全文索引大小保留出足够的空间,
context类型全文索引不是基于事务的,无法保证索引和数据实时同步,DML完成后,如果在全文索引中查不到键值时,可以通过手工or定时任务来刷新同步,
而B-tree、位图都是实时的。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/7901922/viewspace-1060011/ ,如需转载,请注明出处,否则将追究法律责任。