更新时间:2022-09-11 15:17:56
[20140904]关于位图联结索引.txt
--昨天有人问这个问题,自己也忘了差不多,晚上翻书看了一下,做一个记录。
1.建立测试环境:
SCOTT@test> @ver
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
SCOTT@test> alter session set statistics_level=all;
Session altered.
SCOTT@test> select count(*) from emp,dept where dept.deptno=emp.deptno and dept.dname='SALES';
COUNT(*)
----------
6
SCOTT@test> @dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID f24ygm87y6ynz, child number 1
-------------------------------------
select count(*) from emp,dept where dept.deptno=emp.deptno and dept.dname='SALES'
Plan hash value: 1546158010
------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 8 (100)| 1 |00:00:00.01 | 14 | | | |
| 1 | SORT AGGREGATE | | 1 | 1 | | 1 |00:00:00.01 | 14 | | | |
|* 2 | HASH JOIN | | 1 | 5 | 8 (13)| 6 |00:00:00.01 | 14 | 1517K| 1517K| 393K (0)|
|* 3 | TABLE ACCESS FULL| DEPT | 1 | 1 | 4 (0)| 1 |00:00:00.01 | 8 | | | |
| 4 | TABLE ACCESS FULL| EMP | 1 | 14 | 3 (0)| 14 |00:00:00.01 | 6 | | | |
------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("DEPT"."DEPTNO"="EMP"."DEPTNO")
3 - filter("DEPT"."DNAME"='SALES')
2.测试:
--如果建立位图联结索引:
create bitmap index ib_emp_dname on emp(d.dname) from emp e,dept d where e.deptno=d.deptno;
--可以发现语法怪怪的,对dept.dname列建立索引,这个索引不是指向dept表,而是指向emp表。
SCOTT@test> create bitmap index ib_emp_dname on emp(d.dname) from emp e,dept d where e.deptno=d.deptno;
Index created.
SCOTT@test> select count(*) from emp,dept where dept.deptno=emp.deptno and dept.dname='SALES';
COUNT(*)
----------
6
SCOTT@test> @dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID f24ygm87y6ynz, child number 1
-------------------------------------
select count(*) from emp,dept where dept.deptno=emp.deptno and dept.dname='SALES'
Plan hash value: 722388488
-------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 (100)| 1 |00:00:00.01 | 1 |
| 1 | SORT AGGREGATE | | 1 | 1 | | 1 |00:00:00.01 | 1 |
| 2 | BITMAP CONVERSION COUNT | | 1 | 5 | 1 (0)| 1 |00:00:00.01 | 1 |
|* 3 | BITMAP INDEX SINGLE VALUE| IB_EMP_DNAME | 1 | | | 1 |00:00:00.01 | 1 |
-------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("EMP"."SYS_NC00009$"='SALES')
--可以发现执行计划仅仅扫描IB_EMP_DNAME索引,就知道结果,没有扫描表dept以及emp。注意一些细节,access("EMP"."SYS_NC00009$"='SALES')。
SCOTT@test> select emp.*,SYS_NC00009$ from emp;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO SYS_NC00009$
---------- ---------- --------- ---------- ------------------- ---------- ---------- ---------- --------------
7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20
7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 1600 300 30
7521 WARD SALESMAN 7698 1981-02-22 00:00:00 1250 500 30
7566 JONES MANAGER 7839 1981-04-02 00:00:00 2975 20
7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250 1400 30
7698 BLAKE MANAGER 7839 1981-05-01 00:00:00 2850 30
7782 CLARK MANAGER 7839 1981-06-09 00:00:00 2450 10
7788 SCOTT ANALYST 7566 1987-04-19 00:00:00 3000 20
7839 KING PRESIDENT 1981-11-17 00:00:00 5000 10
7844 TURNER SALESMAN 7698 1981-09-08 00:00:00 1500 0 30
7876 ADAMS CLERK 7788 1987-05-23 00:00:00 1100 20
7900 JAMES CLERK 7698 1981-12-03 00:00:00 950 30
7902 FORD ANALYST 7566 1981-12-03 00:00:00 3000 20
7934 MILLER CLERK 7782 1982-01-23 00:00:00 1300 10
14 rows selected.
--可以发现SYS_NC00009$并没有信息输出。仅仅跟dept表联结后才有效。
SCOTT@test> select /*+ index(emp,ib_emp_dname) */emp.*,emp.sys_nc00009$,dept.dname from emp,dept where emp.deptno=dept.deptno and dname='SALES';
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO SYS_NC00009$ DNAME
---------- ---------- --------- ---------- ------------------- ---------- ---------- ---------- -------------- --------------
7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00 1600 300 30 SALES SALES
7521 WARD SALESMAN 7698 1981-02-22 00:00:00 1250 500 30 SALES SALES
7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00 1250 1400 30 SALES SALES
7698 BLAKE MANAGER 7839 1981-05-01 00:00:00 2850 30 SALES SALES
7844 TURNER SALESMAN 7698 1981-09-08 00:00:00 1500 0 30 SALES SALES
7900 JAMES CLERK 7698 1981-12-03 00:00:00 950 30 SALES SALES
6 rows selected.
3.转储索引看看。
SCOTT@test> select segment_name,header_file,header_block from dba_segments where owner=user and segment_name='IB_EMP_DNAME';
SEGMENT_NAME HEADER_FILE HEADER_BLOCK
-------------------- ----------- ------------
IB_EMP_DNAME 4 1914
SCOTT@test> alter system dump datafile 4 block 1915 ;
System altered.
--表很小,索引应该仅仅root节点,应该在HEADER_BLOCK的下1块。
Block header dump: 0x0100077b
Object id on Block? Y
seg/obj: 0x4704a csc: 0x02.a639a65a itc: 2 flg: E typ: 2 - INDEX
brn: 0 bdba: 0x1000778 ver: 0x01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
0x02 0xffff.000.00000000 0x00000000.0000.00 C--- 0 scn 0x0002.a639a65a
Leaf block dump
===============
header address 182929646180=0x2a9774e264
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 4
kdxcosdc 0
kdxconro 3
kdxcofbo 42=0x2a
kdxcofeo 7946=0x1f0a
kdxcoavs 7904
kdxlespl 0
kdxlende 0
kdxlenxt 0=0x0
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 8032
row#0[8001] flag: ------, lock: 0, len=31
col 0; len 10; (10): 41 43 43 4f 55 4e 54 49 4e 47
col 1; len 6; (6): 01 00 00 97 00 00
col 2; len 6; (6): 01 00 00 97 00 0f
col 3; len 3; (3): c9 40 21
row#1[7972] flag: ------, lock: 0, len=29
col 0; len 8; (8): 52 45 53 45 41 52 43 48
col 1; len 6; (6): 01 00 00 97 00 00
col 2; len 6; (6): 01 00 00 97 00 0f
col 3; len 3; (3): c9 89 14
row#2[7946] flag: ------, lock: 0, len=26
col 0; len 5; (5): 53 41 4c 45 53
col 1; len 6; (6): 01 00 00 97 00 00
col 2; len 6; (6): 01 00 00 97 00 0f
col 3; len 3; (3): c9 36 0a
----- end of leaf block dump -----
End dump data blocks tsn: 4 file#: 4 minblk 1915 maxblk 1915
SCOTT@test> select rowid,emp.* from emp;
ROWID EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
------------------ ---------- ---------- --------- ---------- ------------------- ---------- ---------- ----------
AAAR3xAAEAAAACXAAA 7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20
...
SCOTT@test> @lookup_rowid AAAR3xAAEAAAACXAAA
OBJECT FILE BLOCK ROW DBA TEXT
---------- ---------- ---------- ---------- -------------------- ----------------------------------------
73201 4 151 0 4,151 alter system dump datafile 4 block 151 ;
SCOTT@test> select deptno,dname,dump(dname,16) c50 from dept ;
DEPTNO DNAME C50
---------- -------------- --------------------------------------------------
10 ACCOUNTING Typ=1 Len=10: 41,43,43,4f,55,4e,54,49,4e,47
20 RESEARCH Typ=1 Len=8: 52,45,53,45,41,52,43,48
30 SALES Typ=1 Len=5: 53,41,4c,45,53
40 OPERATIONS Typ=1 Len=10: 4f,50,45,52,41,54,49,4f,4e,53
SCOTT@test> select * from emp where deptno=40 ;
no rows selected
SCOTT@test> host cat /home/oracle11g/sqllaji/dfb.sql
select
dbms_utility.data_block_address_file(to_number('&1','xxxxxxxxxxxxxxxx')) rfile#,
dbms_utility.data_block_address_block(to_number('&&1','xxxxxxxxxxxxxxxx')) block#
from dual;
select 'alter system dump datafile '||dbms_utility.data_block_address_file(to_number('&1','xxxxxxxxxxxxxxxx'))||' block '||
dbms_utility.data_block_address_block(to_number('&&1','xxxxxxxxxxxxxxxx')) ||' ;' text
from dual;
SCOTT@test> @dfb 01000097
RFILE# BLOCK#
------- -------
4 151
TEXT
----------------------------------------
alter system dump datafile 4 block 151 ;
--对比上面发现dname='OPERATIONS'不在索引中,因为emp不存在deptno=40的记录。
--看看转储就很容易明白,col 0对应是dept.dname键值,col 1: 开始rowid,col 2: 结束rowid,col 3 : 对应的位图值。
3.位图索引引起阻塞的问题:
--一般位图索引不合适oltp系统,从前面看位图联结索引一样存在这样的问题,做1个简单的测试:
--session 1:
SCOTT@test> insert into emp(empno,hiredate,deptno) values(9999,sysdate,40);
1 row created.
--session 2:
SCOTT@test> insert into emp(empno,hiredate,deptno) values(9998,sysdate,40);
--可以发现会话2挂起!
--roollback插入操作。另外注意连接键值必须是主键。