最近执行一个存储时,发现过程2个问题:
描述:gs_tile_p表:有一个空间索引INDEX_GS_TILE_P,数据为几千万。
IDX_F_RACK_S_FID(在GWM_FID字段),IDX_F_RACK_S_G3EFID(在G3E_FID字段);
其空间索引为INDEX_F_RACK_S_SPATIAL。
第一个问题:
出问题的语句:
from gs_tile_p a, VF_RACK_S b
where b.gwm_vno = 25700
and b.deletetag = 0
and b.gwm_status = 0
and sdo_relate(a.gwm_geometry, b.gwm_geometry, 'MASK = ANYINTERACT') =
'TRUE'
and not exists (select 1
from F_TILE_RACK h
where h.gwm_fid = b.gwm_fid
and h.TILEID >= 864691128723570689
and h.gwm_vno = 25700)
查看该语句的执行计划如下:
该执行计划没有用到INDEX_GS_TILE_P索引,因此导致该语句无法查询出结果。
不走该索引的原因分析:2011-6-17修改
1)进行空间分析的表含有多个索引在语句中被使用,而且空间分析为多个表,容易使索引失效;可以试试使用hint(/*+ noindex(tablename,indexname)*/).
或者直接将iDX_F_RACK_S_DEL该索引删除。
2)表数据问题:如果 筛选的条件占了视图中数据的大部分,且加了 not exists 之后,sql语句的复杂度增加了,所以oracle
认为这个语句应该去全表扫描gs_tile_p。可以考虑使用minus替代not exists。
但是这个不走索引的原因很多,比如上述语句在不同的数据库还不一样,在我自己的数据库中数据量基本是一样的,但是却可以很快查询出来,当然也用到了空间索引。
最近发现进行空间分析时, 使用sdo_relate空间操作符时,;
如该语句sdo_relate(a.gwm_geometry, b.gwm_geometry, 'MASK = ANYINTERACT') = 'TRUE',尽量将表数据量大的放在第一个位置,这样可以查询快很多。
第二个问题:b树索引被转换为位图索引
语句:
select GWM_FID, GWM_FNO, GWM_VNO, tile_id Tileid, districtid
from (select k.*,
row_number() over(partition by GWM_VNO, GWM_FID, tile_id order by tile_id) r
from (select GWM_FID,
GWM_FNO,
GWM_VNO,
GWM_INCREMENT_SPATIAL.getNextLayerTileId(tileid, 11) tile_id,
districtid
from L_TILE_STREETCENTER b
Where deletetag = 0
and gwm_vno = 24849
and b.tileid >= 864691128723570689
and b.tileid <= 864692227966767104
and not exists
(select 1
from L_TILE_STREETCENTER d
where d.gwm_fid = b.gwm_fid
and d.gwm_vno = 24849
and d.tileid >= 792633534685642753
and d.tileid <= 792634084173023232)) k)
where r = 1
其执行计划如下:
该语句始终查询不出来
而且查询计划让我感觉很奇怪,怎么会有位图索引(bitmap conversion from rowids,bitmap conversion to rowids),我根本就没有对L_TILE_STREETCENTER这个表建位图索引。
原来是系统中把B树索引转换为bitmap索引。
该转换由隐藏参数_b_tree_bitmap_plans决定。如果该参数为true,则进行转换,否则不进行转换。而8i里,该参数缺省为false; 而到了9i里,该参数缺省为true了,则对任何索引都有可能进行bitmap转换。
如果将_b_tree_bitmap_plans参数改为false即
alter system set "_b_tree_bitmap_plans"=false;
Select Name ,Value From v$parameter Where Name ='_b_tree_bitmap_plans'
重新查看执行计划 发现没有转换为位图索引,sql语句也可以查询出来了。
但是仍然搞不明白,为什么会发生索引的转换呢?
发生b树索引转换为位图索引的原因:表统计信息不对,重新对表进行分析(begin dbms_stats.gather_table_stats ('GWM','L_TILE_STREETCENTER');END;),执行计划就正常了。
发生b*tree索引转为位图索引,也许执行计划也是正确的,但是仍然进行了转换,这个时候就需要测试下转换与不转换两者的性能,执行转换都需要消耗较多的CPU,因此要谨慎这种转换,如果不想修改隐含参数_b_tree_bitmap_plans的值,可以在语句中采用hint的方式(/*+ opt_param('_b_tree_bitmap_plans', 'false') */)强制不进行转换。
表分析后该sql语句的执行计划如下:
b树索引不再被转换为位图索引后,查询速度仍比较慢,发现与其它设施相比,该sql语句的执行计划有一个索引没有用到即IDX_L_TILE_STREETCENTERTILEDD(create index IDX_L_TILE_STREETCENTERTILEDD on L_TILE_STREETCENTER (TILEID, GWM_FNO, DELETETAG))。为什么会没引用该索引呢?
原因分析:查询的数据占用表的数据大部分,因此CBO认为全表扫描更好。
如果改为查询tileid范围小点就可以使用索引。
引申:
查看oracle隐含参数的设置情况(sys用户查看):
select x.ksppinm name,
y.ksppstvl value,
y.ksppstdf isdefault,
decode(bitand(y.ksppstvf, 7),
1,
'MODIFIED',
4,
'SYSTEM_MOD',
'FALSE') ismod,
decode(bitand(y.ksppstvf, 2), 2, 'TRUE', 'FALSE') isadj
from sys.x$ksppi x, sys.x$ksppcv y
where x.inst_id = userenv('Instance')
and y.inst_id = userenv('Instance')
and x.indx = y.indx
and x.ksppinm like '%_&par%'
order by translate(x.ksppinm, ' _', ' ')