我在带有多个索引的Oracle 10g数据库中有一个数据恢复查询。执行分页时,oracle停止使用索引。
对于第一页的查询,只生成一个子查询:
解释计划select * from (
SELECT e.id, e.data, e.date, e.modifdate, e.origin, e.type, e.priority, e.view, e.state
FROM ev e
WHERE exists (
SELECT null
FROM dev d
WHERE (e.cId = d.deviceId OR e.cId = d.id) AND d.id = 152465)
ORDER BY e.date DESC )
where rownum <= 30
在执行计划中,我可以看到索引的使用方式:
----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 30 | 68730 | 35616 (1)| 00:07:08 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | VIEW | | 30 | 68730 | 35616 (1)| 00:07:08 |
|* 3 | FILTER | | | | | |
| 4 | TABLE ACCESS BY INDEX ROWID | EV | 90578 | 138M| 31351 (1)| 00:06:17 |
| 5 | INDEX FULL SCAN | EV_DATE_DESC_IDX | 35291 | | 128 (6)| 00:00:02 |
|* 6 | TABLE ACCESS BY INDEX ROWID | DEV | 1 | 20 | 4 (0)| 00:00:01 |
| 7 | BITMAP CONVERSION TO ROWIDS | | | | | |
| 8 | BITMAP OR | | | | | |
| 9 | BITMAP CONVERSION FROM ROWIDS| | | | | |
|* 10 | INDEX RANGE SCAN | DEV_DEVICE_ID_IDX | | | 1 (0)| 00:00:01 |
| 11 | BITMAP CONVERSION FROM ROWIDS| | | | | |
|* 12 | INDEX RANGE SCAN | SYS_C00443004 | | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------------
0.759秒30行
对于以下页面,将生成两个子查询,并且不再使用索引:
explain plan for
select * from (
select row_.*, rownum rownum_ from (
SELECT e.id, e.data, e.date, e.modifdate, e.origin, e.type, e.priority, e.view, e.state
FROM ev e
WHERE exists (
SELECT null
FROM dev d
WHERE (e.cId = d.deviceId OR e.cId = d.id) AND d.id = 152465)
ORDER BY e.date DESC )
row_ where rownum <= 60)
where rownum_ > 30
执行计划:
--------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 60 | 135K| | 63815 (2)| 00:12:46 |
|* 1 | VIEW | | 60 | 135K| | 63815 (2)| 00:12:46 |
|* 2 | COUNT STOPKEY | | | | | | |
| 3 | VIEW | | 77 | 172K| | 63815 (2)| 00:12:46 |
|* 4 | SORT ORDER BY STOPKEY | | 77 | 120K| 283M| 63815 (2)| 00:12:46 |
|* 5 | FILTER | | | | | | |
| 6 | TABLE ACCESS FULL | EV | 90578 | 138M| | 6798 (3)| 00:01:22 |
|* 7 | TABLE ACCESS BY INDEX ROWID | DEV | 1 | 20 | | 4 (0)| 00:00:01 |
| 8 | BITMAP CONVERSION TO ROWIDS | | | | | | |
| 9 | BITMAP OR | | | | | | |
| 10 | BITMAP CONVERSION FROM ROWIDS| | | | | | |
|* 11 | INDEX RANGE SCAN | DEV_DEVICE_ID_IDX | | | | 1 (0)| 00:00:01 |
| 12 | BITMAP CONVERSION FROM ROWIDS| | | | | | |
|* 13 | INDEX RANGE SCAN | SYS_C00443004 | | | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------------------------------
3.386秒30行
对于分页,我手工编写查询但我使用实体管理器设置页码:
Query querySelect = entityManager.createNativeQuery(query, Event.class);
querySelect.setMaxResults(pageSize);
querySelect.setFirstResult(pageSize * page);
为什么Oracle不在第二个查询中使用索引?如何在oracle中使用带分页的索引?
答案 0 :(得分:0)
假设这些是正常的堆表,我只是在这里推测。
第一个查询使用ev.date列对记录进行排序,并获取前30个记录。这有利于索引全扫描(IFS)。 IFS以叶块中相同的条目顺序扫描ROWID(从左到右 - 全扫描)。因此扫描的记录已经订购。当您从这些中获取前30行时,优化器似乎更喜欢IFS。请注意,IFS之后可以访问桌子。这已经是一个开销。
第二个查询在扫描的记录之间提取30行,与第一个查询中的前30个记录不同。这将在扫描结果集之间创建一个新的起点和终点。尽管按顺序扫描,查询将不得不根据新的起点丢弃最初扫描的行。因此,在起点之前扫描的记录是多余的,因为它们无论如何都会被过滤掉。所以看起来IFS在这里被视为开销。这可能迫使查询支持针对IFS的全表扫描(FTS)。此外,需要对扫描的记录进行排序,以使用283M的临时表空间来获取所需的顺序。
您可能需要查看以下详细信息,以便更好地了解执行计划。
EV中的行数
SELECT num_rows,last_analyzed,blocks,sample_size FROM user_tables 表格=&#39; EV&#39;;
DEV中的行数
SELECT num_rows,last_analyzed,blocks,sample_size FROM user_tables 表格=&#39; DEV&#39;;
DEV中ID = 152465
每个表中的索引列表,其中列按顺序排列,唯一性
SELECT table_name,index_name,uniqueness,clustering_factor,last_analyzed,sample_size FROM user_indexes 表格中的表格(&#39; EV&#39;,&#39; DEV&#39;)和状态=&#39;有效&#39; 订购1,2;
SELECT table_name,index_name,column_name FROM user_ind_columns 表格中的表格(&#39; EV&#39;,&#39; DEV&#39;) ORDER BY 1,2,column_position;
检查任何列上是否有直方图统计信息。
SELECT table_name,column_name,histogram FROM user_tab_col_statistics 表格中的表格(&#39; EV&#39;,&#39; DEV&#39;) ORDER BY 1,2;
以下参数也可能有所帮助。
optimizer_index_caching的 OPTIMIZER_INDEX_COST_ADJ DB_FILE_MULTIBLOCK_READ_COUNT PGA_AGGREGATE_TARGET OPTIMIZER_MODE CURSOR_SHARING