索引不适用于使用oracle 10g进行分页的查询

时间:2018-03-07 19:04:48

标签: sql oracle indexing oracle10g

我在带有多个索引的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中使用带分页的索引?

1 个答案:

答案 0 :(得分:0)

假设这些是正常的堆表,我只是在这里推测。

第一个查询使用ev.date列对记录进行排序,并获取前30个记录。这有利于索引全扫描(IFS)。 IFS以叶块中相同的条目顺序扫描ROWID(从左到右 - 全扫描)。因此扫描的记录已经订购。当您从这些中获取前30行时,优化器似乎更喜欢IFS。请注意,IFS之后可以访问桌子。这已经是一个开销。

第二个查询在扫描的记录之间提取30行,与第一个查询中的前30个记录不同。这将在扫描结果集之间创建一个新的起点和终点。尽管按顺序扫描,查询将不得不根据新的起点丢弃最初扫描的行。因此,在起点之前扫描的记录是多余的,因为它们无论如何都会被过滤掉。所以看起来IFS在这里被视为开销。这可能迫使查询支持针对IFS的全表扫描(FTS)。此外,需要对扫描的记录进行排序,以使用283M的临时表空间来获取所需的顺序。

您可能需要查看以下详细信息,以便更好地了解执行计划。

  1. EV中的行数

    SELECT num_rows,last_analyzed,blocks,sample_size   FROM user_tables  表格=&#39; EV&#39;;

  2. DEV中的行数

    SELECT num_rows,last_analyzed,blocks,sample_size   FROM user_tables  表格=&#39; DEV&#39;;

  3. DEV中ID = 152465

  4. 的行数
  5. EV或ID为DEVICEID = 152465
  6. 的行数
  7. 每个表中的索引列表,其中列按顺序排列,唯一性

    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;

  8. 检查任何列上是否有直方图统计信息。

    SELECT table_name,column_name,histogram   FROM user_tab_col_statistics  表格中的表格(&#39; EV&#39;,&#39; DEV&#39;) ORDER BY 1,2;

  9. 以下参数也可能有所帮助。

    optimizer_index_caching的 OPTIMIZER_INDEX_COST_ADJ DB_FILE_MULTIBLOCK_READ_COUNT PGA_AGGREGATE_TARGET OPTIMIZER_MODE CURSOR_SHARING