索引扫描导致大量物理读取(Oracle)

时间:2015-05-22 08:45:29

标签: sql indexing oracle11g pagination query-performance

有两张表格超过 2000万的记录。数据库版本为Oracle 11.2.0.3.13标准版

SQL> select count(*) from atsd_tra_trade_print;

  COUNT(*)
----------
  20000000

SQL> select count(*) from atsd_mob_allocation_pos;

  COUNT(*)
----------
  20551780

我们对表运行以下查询。 查询结构类似。查询用于分页。 两个查询的排序列都已编入索引,并且不包含任何NULL值。查询和相应的autotrace输出/计划如下所示。

索引 INDX_ATTP_6 在ATSD_TRA_TRADE_PRINT( TRANSACT_TIME )上创建

索引 INDX_AMAP_6 是在ATSD_MOB_SETTLEMENT_POS上创建的( DATE_TIME

索引的基数如下

INDX_ATTP_6 - 5972

INDX_AMAP_6 - 5974

上述两列的数据类型为 varchar2

在刷新buffer_cache 后,两个查询都运行。还收集了模式统计数据。

SELECT * FROM ( SELECT T2.*, ROWNUM AS RN FROM (
SELECT *
FROM ATSDN_TRA_TRADE_PRINT T
WHERE LATEST = 1
ORDER BY TRANSACT_TIME) T2)
WHERE RN > 0 and ROWNUM <= 28;

输出:

28 rows selected.

Elapsed: 00:00:00.16

Execution Plan
----------------------------------------------------------
Plan hash value: 3823692003

-------------------------------------------------------------------------    -------------------------------
| Id  | Operation           | Name             | Rows  | Bytes | Cost     (%CPU)| Time     |
-------------------------------------------------------------------------    -------------------------------
|   0 | SELECT STATEMENT        |              |    28 | 60060 |     8       (0)| 00:00:01 |
|*  1 |  COUNT STOPKEY          |              |       |       |        |              |
|*  2 |   VIEW              |              |    28 | 60060 |     8   (0)|     00:00:01 |
|   3 |    COUNT            |              |       |       |        |             |
|   4 |     VIEW            |              |    28 | 59696 |     8   (0)|     00:00:01 |
|*  5 |      TABLE ACCESS BY INDEX ROWID| ATSD_TRA_TRADE_PRINT |  7488K|      3234M|     8   (0)| 00:00:01 |
|   6 |       INDEX FULL SCAN       | INDX_ATTP_6          |    57 |           |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------    -------------------------------

Predicate Information (identified by operation id):
 ---------------------------------------------------

   1 - filter(ROWNUM<=28)
   2 - filter("RN">0)
   5 - filter("LATEST"=1)


Statistics
----------------------------------------------------------
    571  recursive calls
      0  db block gets
    948  consistent gets
     49  physical reads
      0  redo size
  18586  bytes sent via SQL*Net to client
    535  bytes received via SQL*Net from client
      3  SQL*Net roundtrips to/from client
     29  sorts (memory)
      0  sorts (disk)
     28  rows processed

上述查询按预期快速执行。但是对另一个表的查询会导致执行时间过长。我能看到的唯一观察是有大量的物理读取。两个查询执行计划看起来都很相似。

SELECT * FROM ( SELECT T2.*, ROWNUM as RN FROM ( 
SELECT *
FROM ATSD_MOB_ALLOCATION_POS AL
WHERE  LATEST = 1
ORDER BY DATE_TIME) T2)
WHERE RN > 0 and ROWNUM <= 28;

输出:

28 rows selected.

Elapsed: 00:01:52.28

Execution Plan
----------------------------------------------------------
Plan hash value: 884170602

-------------------------------------------------------------------------    ----------------------------------
| Id  | Operation           | Name            | Rows  | Bytes | Cost     (%CPU)| Time     |
-------------------------------------------------------------------------    ----------------------------------
|   0 | SELECT STATEMENT        |             |    28 | 38892 | 7   (0)|     00:00:01 |
|*  1 |  COUNT STOPKEY          |             |   |   |        |      |
|*  2 |   VIEW              |             |    28 | 38892 | 7   (0)|     00:00:01 |
|   3 |    COUNT            |             |   |   |        |      |
|   4 |     VIEW            |             |    28 | 38528 | 7   (0)|     00:00:01 |
|*  5 |      TABLE ACCESS BY INDEX ROWID| ATSD_MOB_ALLOCATION_POS |        14M|  5863M| 7   (0)| 00:00:01 |
|   6 |       INDEX FULL SCAN       | INDX_AMAP_6         |    39 |   | 4       (0)| 00:00:01 |
-------------------------------------------------------------------------    ----------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(ROWNUM<=28)
   2 - filter("RN">0)
   5 - filter("LATEST"=1)


Statistics
----------------------------------------------------------
    281  recursive calls
      0  db block gets
 335395  consistent gets
 332763  physical reads
    116  redo size
  13582  bytes sent via SQL*Net to client
    535  bytes received via SQL*Net from client
      3  SQL*Net roundtrips to/from client
     17  sorts (memory)
      0  sorts (disk)
     28  rows processed

有人可以告诉我为什么会这样。在此先感谢... :)

1 个答案:

答案 0 :(得分:0)

问题在于索引结构......当它以asc方式遍历索引INDX_AMAP_6时,它必须在满足过滤条件的行之前读取500万条记录&#34; LATEST = 1&#34 ;。排序列和文件管理器列上的复合索引解决了这个问题。

在atsd_mob_allocation_pos上创建索引AMAP_TEST1(最新,date_time);