在Oracle DB中获取数据太慢(查询比较)

时间:2015-01-27 18:20:13

标签: oracle

我遇到了以下问题: 我有一个包含超过1,000,000,000个数据的表。现在我运行以下查询(acc_no是主键):

select acc_no from user where acc_no between 753976276998100 and 78776276998199

上述查询在不到一秒的时间内运行并获取了100,000条记录

但如果我在同一个查询中再添加一列(" service_no"),

select acc_no,service_no from user where acc_no between 753976276998100 and 78776276998199

..花了一分多钟。这是为什么?为什么第一个查询花了不到一秒钟,第二个查询花了不到一分钟?

仅供参考:service_no是NUMBER列

1 个答案:

答案 0 :(得分:7)

如果查看两个查询的执行计划,您将看到第一个查询仅通过索引范围扫描来实现:

explain plan for
select acc_no from t42
where acc_no between 753976276998100 and 78776276998199;

select * from table (dbms_xplan.display);

----------------------------------------------------------------------------------
| Id  | Operation         | Name         | Rows  | Bytes | Cost (%CPU)| Time     |     
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |              |     1 |    10 |     0   (0)|          |
|*  1 |  FILTER           |              |       |       |            |          |
|*  2 |   INDEX RANGE SCAN| SYS_C0090827 |     1 |    10 |     2   (0)| 00:00:01 |
----------------------------------------------------------------------------------

......可以很快;但是第二个查询还有一个额外的步骤,即索引rowid的表访问:

explain plan for
select acc_no, service_no from t42
where acc_no between 753976276998100 and 78776276998199;

select * from table (dbms_xplan.display);

---------------------------------------------------------------------------------------------
| Id  | Operation                    | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |              |     1 |    14 |     0   (0)|          |
|*  1 |  FILTER                      |              |       |       |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| T42          |     1 |    14 |     3   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | SYS_C0090827 |     1 |       |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

当您只查询索引中存在的列 - 在这种情况下acc_no(在主键的支持索引中)时,只需触及索引。无需查看已有索引列的值的基础表数据。

当您的选择列表包含索引中的列时,还必须检索表数据,因为另一列 - service_no不在索引中。这是另一个磁盘操作访问表段中的数据块。表数据可能分散在比索引更多的块上,这会放大效果,因为您可能需要为每个匹配行获取不同的块。

基本上,它需要做更多工作才能从磁盘访问更多数据,因此需要更长的时间。