Oracle DB 中取数据太慢(查询对比)

Fetching data is too slow in Oracle DB (query comparison)

我遇到了以下问题: 我有一个 table 超过 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 列

如果您查看这两个查询的执行计划,您会发现第一个查询仅通过索引范围扫描完成:

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 |
----------------------------------------------------------------------------------

...这可能相当快;但是第二个查询有一个额外的步骤,table 通过索引 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 在本例中,它位于主键的支持索引中 - 只需要触及索引。无需查看基础 table 数据以获得索引列中已有的值。

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

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