代码改变世界

ITPUB:分区表,每次查询取出1%的记录,为什么没有走索引?

2011-05-31 10:39  Tracy.  阅读(562)  评论(0编辑  收藏  举报

分区表,每次查询取出1%的记录,为什么没有走索引?

目前情况:
windows2003系统, 11gR1版本。
经常执行的是类似:select * from rece where gpsdate >= ... and gpsdate<=... and device_number=... ; 的查询,即:查询某个设备号的设备,在某些天内的记录。而rece表里共有3亿条记录。
所以,
1, 设计rece为分区表,其中的gpsdate上建立了list分区,每天的数据放入一个list分区内。每个分区的记录约为300万行。
2, 在device_number 列上,建立局部索引,
create index idx_rece_device_number on rece(device_number) local ;
通过 SELECT segment_name, partition_name, tablespace_name
FROM user_segments
WHERE segment_name = 'IDX_rece_DEVICE_NUMBER'; 可以看到,device_number 列上已经建立了分区索引了。
但是,却发现执行 select * from rece where gpsdate >= '20100501' and gpsdate<='2010
0504' and device_number='900000015' ;语句时,默认不走索引?只有加hint后,才走索引,搞不清楚什么原因?
不明白的原因是:gpsdate是分区的列,而 device_number 列上确实已经有了local索引,为什么 默认还不走索引呢?
具体的trace信息如下:
SQL> set autotrace traceonly;
SQL> select * from rece where gpsdate >= '20100501' and gpsdate<='2010
0504' and device_number='900000015' ;
已选择146663行。
执行计划
----------------------------------------------------------
Plan hash value: 2550857439
--------------------------------------------------------------------------------
-----------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Tim
e | Pstart| Pstop |
--------------------------------------------------------------------------------
-----------------------
| 0 | SELECT STATEMENT | | 170K| 16M| 92991 (1)| 00:
18:36 | | |
| 1 | PARTITION LIST ITERATOR| | 170K| 16M| 92991 (1)| 00:
18:36 | KEY | KEY |
|* 2 | TABLE ACCESS FULL | rece | 170K| 16M| 92991 (1)| 00:
18:36 | KEY | KEY |
--------------------------------------------------------------------------------
-----------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("DEVICE_NUMBER"='900000015')
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
350177 consistent gets
340572 physical reads
0 redo size
9840643 bytes sent via SQL*Net to client
108067 bytes received via SQL*Net from client
9779 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
146663 rows processed
SQL> select * from rece where gpsdate = '20100501' and device_number=
'900000015' ;
已选择40396行。
执行计划
----------------------------------------------------------
Plan hash value: 3235688001
--------------------------------------------------------------------------------
---------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
| Pstart| Pstop |
--------------------------------------------------------------------------------
---------------------
| 0 | SELECT STATEMENT | | 50223 | 7651K| 25466 (1)| 00:05
:06 | | |
| 1 | PARTITION LIST SINGLE| | 50223 | 7651K| 25466 (1)| 00:05
:06 | KEY | KEY |
|* 2 | TABLE ACCESS FULL | rece | 50223 | 7651K| 25466 (1)| 00:05
:06 | 1 | 1 |
--------------------------------------------------------------------------------
---------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("DEVICE_NUMBER"='900000015')
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
96370 consistent gets
93737 physical reads
0 redo size
2713261 bytes sent via SQL*Net to client
30143 bytes received via SQL*Net from client
2695 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
40396 rows processed
SQL>
SQL> select /*+ index( rece, idx_rece_device_number) */ * from rece where gpsdate >= '20100501' and gpsdate<='20100504' and device_number
='900000015' ;
已选择146663行。
执行计划
----------------------------------------------------------
Plan hash value: 581505150
--------------------------------------------------------------------------------
----------------------------------------------------
| Id | Operation | Name | Row
s | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------
----------------------------------------------------
| 0 | SELECT STATEMENT | | 1
70K| 16M| 2884K (1)| 09:36:54 | | |
| 1 | PARTITION LIST ITERATOR | | 1
70K| 16M| 2884K (1)| 09:36:54 | KEY | KEY |
| 2 | TABLE ACCESS BY LOCAL INDEX ROWID| rece | 1
70K| 16M| 2884K (1)| 09:36:54 | KEY | KEY |
|* 3 | INDEX RANGE SCAN | IDX_rece_DEVICE_NUMBER | 35
18K| | 10331 (1)| 00:02:04 | KEY | KEY |
--------------------------------------------------------------------------------
----------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("DEVICE_NUMBER"='900000015')
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
131673 consistent gets
101010 physical reads
0 redo size
9840684 bytes sent via SQL*Net to client
108067 bytes received via SQL*Net from client
9779 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
146663 rows processed
我的参数是:
SQL> show parameter optimizer_index_cost_adj
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
optimizer_index_cost_adj integer 100
实在搞不清楚,希望大家指教啊。

---------------------------------------------Tip---------------------------------------------------

你加HINT走索引后逻辑读是131673,而没加HINT全表扫描逻辑读是 96370 ,查询返回的结果是最后的40396 rows processed。前者是获取每行需要131673/40396=3个IO ,后者是平均获取每行需要96370/40396=2个IO ,由此可见开销是索引更大,ORACLE当然不走索引了 。
返回了4万多条记录这个查询的返回确实非常多!这个TABLE ACCESS BY LOCAL INDEX ROWID的开销是离散读, 2884K (1)| 这个有点大,我觉的有可能是clustering_factor太大了。
建议你查询一下索引的聚合因子clustering_factor