我遇到了以下问题: 我有一个包含超过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列
答案 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
不在索引中。这是另一个磁盘操作访问表段中的数据块。表数据可能分散在比索引更多的块上,这会放大效果,因为您可能需要为每个匹配行获取不同的块。
基本上,它需要做更多工作才能从磁盘访问更多数据,因此需要更长的时间。