Bitmap index的主要思想就是,针对每一个可能的值x,建立一个或一组位图映射,每个bit为1代表这个位置的值等于x,为0则不等于x。而每个位置都可以直接映射到某一行的rowid。由于在执行DML操作时,锁定的是整个bitmap,而不是bitmap中的某个位,所以bitmap index对于并发DML的性能很差,而且频繁的DML操作会使得bitmap index的空间效率大打折扣,所以OLTP系统并不合适使用bitmap index。对于基本没有DML操作,有大量ad hoc查询的Data warehouse环境则相当有效。关于bitmap index的理解,可以参考itpub上的一篇深入讨论。
从oracle9i起,oracle又引进了一种新的索引类型:bitmap join index。和bitmap index建立在单个table上不同,bitmap join index是基于多表连接的,连接条件要求是等于的内连接(equi-inner join)。对于数据仓库而言,较普遍的是Fact table的外键列和相关的Dimension table的主键列的连接操作。
Bitmap join index能够消除查询中的连接操作,因为它实际上已经将连接的结果保存在索引当中了。而且,相对于在表的连接列上建普通bitmap index来说,bitmap join index需要更少的存储空间。
同样的基于连接的Metarialized view也可以用来消除连接操作。但bitmap join index比起物化视图来更有效率,因为通过bitmap join index可以直接将基于索引列的查询对应到事实表的rowid。
以oracle的sample schema SH中的sales和customers表做个例子
1.建立基于维度表中一个列的bitmap join index
create bitmap index sales_cust_gender_bjix
on sales(customers.cust_gender)
from sales,customers
where sales.cust_id=customers;
建立这样的bitmap join index后,下面的查询就可以从index中直接得到结果,而不再需要连接sales和custmoers两张表来获得结果了。相当于根据连接条件,将customers表中的cust_gender列保存到sales表中了。
select sum(sales.amount_sold)
from sales,customers
where sales.cust_id,customers.cust_id
and customers.cust_gender='M';
通过将bitmap join index dump出来可以看到,实际上,索引是按照customers.cust_gender分成2个位图,每个位图映射到sales表的ROWID。所以根据customers.cust_gender来过滤连接结果时,从索引中可以直接得到目标数据在sales中的rowid,无须执行join操作了。
一个可能的执行计划如下:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3751 Card=1 Bytes=9)
1 0 SORT (AGGREGATE)
2 1 PARTITION RANGE (ALL)
3 2 TABLE ACCESS (BY LOCAL INDEX ROWID) OF 'SALES' (Cost=3751 Card=508136 Bytes=4573220)
4 3 BITMAP CONVERSION (TO ROWIDS)
5 4 BITMAP INDEX (SINGLE VALUE) OF 'IX_BITMAP'
2.建立基于一个维度表中多个列的bitmap join index
create bitmap index sales_cust_ms_bjix
on sales(customers.cust_gender,customers.cust_id)
from sales,customers
where sales.cust_id=customers.cust_id;
3.建立多个维度表到一个事实表的bitmap join indexcreate bitmap index sales_c_gender_p_cat_bjix
on sales(customers.cust_gender,products.prod_category)
from sales,customers,products
where sales.cust_id=customers.cust_id
and sales.prod_id=products.prod_id;
4.建立基于snowflake schme的bitmap join index
雪花模型的维度表被规范化为多个小表,也就是建index的时候需要额外连接其他几个表
create bitmap index sales_co_country_name_bjix
on sales(countries.country_name)
from sales,countries,customers
where sales.country_id=countries.country_id
and sales.cust_id=customers.cust_id;
Bitmap join index的一些限制条件
只支持CBO
只能是equi-inner连接,任何外连接都无法使用bitmap join index
多个连接条件只能是AND关系
只能在fact table上执行并行DML。如果在dimension table上执行并行DML,会导致索引变为unusable状态。
不同的事务中,只能并发更新一个表
在From字句中,任何一个表都不能出现两次
在索引组织表(IOT)和临时表上不能建立bitmap join index
索引只能基于dimenion table中的列
维度表用于连接的列只能是主键列或者是有唯一约束的列。
SQL> create bitmap index sales_cust_gender_bjix
2 on sales(customers.cust_gender)
3 from sales,customers
4 where sales.cust_id=customers.cust_id;
from sales,customers
*
ERROR at line 3:
ORA-25954: missing primary key or unique constraint on dimension
如果维度表的主键是组合主键,那么连接条件需要是全部主键列都参与
其他对于bitmap index的限制条件同样使用于bitmap join index,比如在分区表上只能是local,不能是global。