2

我有一个负责存储日志的表。DDL 是这样的:

CREATE TABLE LOG(
    "ID_LOG" NUMBER(12,0) NOT NULL ENABLE, 
    "DATA" DATE NOT NULL ENABLE, 
    "OPERATOR_CODE" VARCHAR2(20 BYTE), 
    "STRUCTURE_CODE" VARCHAR2(20 BYTE), 

     CONSTRAINT "LOG_PK" PRIMARY KEY ("ID_LOG")
 );

使用这两个索引:

CREATE INDEX STRUCTURE_CODE ON LOG ("OPERATOR_CODE");

CREATE INDEX LOG_01 ON LOG ("STRUCTURE_CODE", "DATA") ;

但是这个查询会产生一个完整的表扫描:

SELECT log.data AS data1, 
       OPERATOR_CODE,
       STRUCTURE_CODE
  FROM log
 WHERE data BETWEEN to_date('03/03/2008', 'DD-MM-YYYY')
                AND to_date('08/03/2015', 'DD-MM-YYYY')
   AND STRUCTURE_CODE = '1601';

为什么我总是看到一个FULL TABLE SCANon 列DATASTRUCTURE_CODE

(我也尝试过创建两个不同的索引STRUCTURE_CODEDATA但我总是进行全表扫描)

4

2 回答 2

7

您是否在新索引和表上运行了统计信息?

该表中有多少数据以及该查询可能返回的数据百分比是多少?有时,全表扫描更适合小表或将返回大量数据的查询。

于 2015-03-10T14:39:42.343 回答
0
  1. 您在该表中有多少行?
  2. 此查询返回多少?
  3. 请附上解释计划。

如果加载表并执行全表扫描 (FTS) 比使用索引更便宜(IO 成本),则将加载表并发生 FTS。[基本上和Necreaux说的一样]

如果表很小,或者预期的结果集很大就会发生这种情况。

什么是小?如果表小于DB_FILE_MULTIBLOCK_READ_COUNT ,FTS 几乎总是会发生。这种情况下,表通常可以通过一次大读取加载到内存中。这并不总是一个问题,请检查解释计划中的 IO 成本。

什么是大?如果表非常大,并且您将返回其中的大部分,那么在几个大型 IO 调用中读取整个表比进行一些索引读取然后在周围进行大量微小的 IO 调用更便宜桌子。

从您的查询中盲目猜测(没有解释计划结果),我认为它会首先考虑索引范围扫描(超过 LOG_01),然后是通过 rowid 访问表(以获取 OPERATOR_CODE,因为它不在索引中),但是要么它决定您的表太小,要么从该日期范围/结构代码返回太多行,因此滚动表更便宜(以 IO 成本计)。

于 2015-03-10T16:32:59.177 回答