转载地址:http://lzfhope.blog.163.com/blog/static/63639922013119112011947/
以下内容主要都是关于oracle 10g位图索引,重点是存储,其它优缺点,查询机制等也略微介绍,概因为存储机制是根基。
内容主要分四个部分:
1)来源于http://blog.chinaunix.net/uid-20687159-id-1894992.html
2)来源于http://blog.sina.com.cn/s/blog_4c6fef63010085m8.html
3)来自oracle官方文档的和其它一些。
4)个人的试验,看位图索引的情况。
------------------------------
要想升入dw等,了解位图索引是必不可少的。
了解位图索引的关键是知道索引的内部结构,知道结果,自然知道它的优缺点,所以了解结构是核心。
一,oracle官方文档
关于位图索引的概要介绍-定义、查询原理、优点、缺点。
这里只是一个笔记,非官方原文,摘取了纲要内容:
1.定义,什么是位图索引:就是用位图表示的索引,oracle对于选择度底的列的每个键值建立一个位图,位图中的每一位可能对应多个列,位图中位等于1表示特定的行含有此位图表示的键值。
2.查询,由于索引是位图,所以很多很多时候可以对这些索引中的位图进行位运算-(and 和 or),这样的速度明显比b树快(某些情况下)。由于位图索引可以存储null,所以可以直接通过位图索引计数(肯定是准确的)。后面提到的有点和位图的计算方式是直接相关的。
3.位图的优点(主要针对dw):
- 减少即席查询的相应时间
- 和其它类型索引比较,真正节约了索引数据空间
- 即使在非常差的硬件上,也可能会有戏剧化的性能提升
- 高效的并行DML和LOAD操作。
- 生成索引的时候更高效,首先是不排序,其次是占用的空间少(索引空间)。
- 可以通过位图索引直接计数。
4.位图索引的缺点(其它资料),也不好说是缺点
- 不适合选择度底的列
- 如果有比较频繁的insert,update等操作,可能导致性能很底下,因为更新索引用的是行锁(可能锁定多行),而不是排它锁。
- 可能会溢出,索引数据块难于放下整个索引值,这导致低效。
示意图-逻辑分析位图
主要至关了解下位图:
需要注意的是,这只是个示意图,实际上每个位图的位数并非刚好等于记录数,而是会根据情况来分解,否则对于居多的数据而言,位图未免太大了。
深入研究--数据块中如何存储
这是真正的深入了解。
为了省事,暂时不修改原文的样式
一.什么是位图索引 |
四、个人试验,性能比较
crmii.tkhxx有记录1281792,其中yyb=7911的记录共有23537条。
原来有索引idx_khxx(yyb,khh,khxm),但oracle不会去使用,具体原因不用深究。
后又建立位图索引:
create bitmap index idx_b_khxx on khxx(yyb) ;
--先看没用索引的 SQL> explain plan for SELECT /*+NO_INDEX (A idx_b_khxx)*/ * FROM CRMII.TKHXX A WHERE YYB=7911 2 / Explained SQL> select * from table(dbms_xplan.display) 2 / PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Plan hash value: 2975641408 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 27884 | 7107K| 11337 (1)| 00:02:17 | |* 1 | TABLE ACCESS FULL| TKHXX | 27884 | 7107K| 11337 (1)| 00:02:17 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("YYB"=7911) 13 rows selected --再看有用索引的 SQL> explain plan for select * from crmii.tkhxx where yyb=7911 2 / Explained SQL> select * from table(dbms_xplan.display) 2 / PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Plan hash value: 1238075174 -------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| -------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 27884 | 7107K| 6862 (1)| | 1 | TABLE ACCESS BY INDEX ROWID | TKHXX | 27884 | 7107K| 6862 (1)| | 2 | BITMAP CONVERSION TO ROWIDS| | | | | |* 3 | BITMAP INDEX SINGLE VALUE | IDX_B_KHXX | | | | -------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("YYB"=7911) 15 rows selected --位图索引就是这么简单,首先更具单个键值找到对应的位图,然后把位图中的值转换为rowid,再根据rowid访问表格 --就以上这个情况来看,效率提升了大约100% |
再来学学看看下索引数据的存储情况:
CREATE TABLE TEST.TEST_BITMAP(ID INT,SCORE NUMBER); CREATE BITMAP INDEX TEST.IDX_B_TEST_BITMAP ON TEST.TEST_BITMAP(ID); INSERT INTO TEST.TEST_BITMAP VALUES(1,12); INSERT INTO TEST.TEST_BITMAP VALUES(1,13); INSERT INTO TEST.TEST_BITMAP VALUES(1,14); INSERT INTO TEST.TEST_BITMAP VALUES(1,15); INSERT INTO TEST.TEST_BITMAP VALUES(1,16); INSERT INTO TEST.TEST_BITMAP VALUES(1,17); INSERT INTO TEST.TEST_BITMAP VALUES(1,18); INSERT INTO TEST.TEST_BITMAP VALUES(1,19); INSERT INTO TEST.TEST_BITMAP SELECT ID+1,SCORE*2 FROM TEST.TEST_BITMAP; INSERT INTO TEST.TEST_BITMAP SELECT ID+1,LN(SCORE) FROM TEST.TEST_BITMAP; COMMIT; SQL> select count(*) from test.test_bitmap 2 / COUNT(*) ---------- 32 SQL> select header_file,header_block,blocks,bytes from dba_segments where segment_name='IDX_B_TEST_BITMAP' and owner='TEST' 2 / HEADER_FILE HEADER_BLOCK BLOCKS BYTES ----------- ------------ ---------- ---------- 205 1515 8 65536 SQL> ALTER SYSTEM DUMP DATAFILE 205 BLOCK MIN 1515 BLOCK MAX 1522 查看文件: row#0[7789] flag: ------, lock: 2, len=28 col 0; len 2; (2): c1 02 col 1; len 6; (6): 00 00 00 00 00 00 col 2; len 6; (6): 33 40 05 e8 00 07 col 3; len 8; (8): f8 c2 ca 88 f2 a9 02 ff row#1[7712] flag: ------, lock: 2, len=29 col 0; len 2; (2): c1 03 col 1; len 6; (6): 00 00 00 00 00 00 col 2; len 6; (6): 33 40 05 e8 00 17 col 3; len 9; (9): f9 c3 ca 88 f2 a9 02 ff ff row#2[7664] flag: ------, lock: 2, len=28 col 0; len 2; (2): c1 04 col 1; len 6; (6): 00 00 00 00 00 00 col 2; len 6; (6): 33 40 05 e8 00 1f col 3; len 8; (8): f8 c5 ca 88 f2 a9 02 ff 前文说col 0是 可以转为具体的键值,可以通过dbms_stats.convert_raw_value直接转,对于varchar2好像是这样, 但是对于int或者number则不是这样的。这得从数值的存储方式说起,有关数值存储可以看 http://www.linuxidc.com/Linux/2011-01/31375.htm col 0; len 2; (2): c1 02 这里c1转为10进制=to_number('c1','xxxx')=193, 02就是2 ,结果和dump(1)的 “Typ=2 Len=2: 193,2”后面相等,不过少了长度和类型。 |