我有一个负责存储日志的表。 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") ;
但是这个查询产生了一个FULL TABLE SCAN:
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 SCAN
和DATA
列上看到STRUCTURE_CODE
?
(我也试过为STRUCTURE_CODE
和DATA
创建两个不同的索引,但我总是进行全表扫描)
答案 0 :(得分:7)
您是否在新索引和表格上运行了统计信息?
该表中有多少数据以及该查询可能返回的百分比是多少?有时,对于小型表或将返回大部分数据的查询,全表扫描更好。
答案 1 :(得分:0)
如果加载表并进行全表扫描(FTS)比使用索引更便宜(在IO成本中),则表将被加载并且将发生FTS。 [基本上与Necreaux所说的相同]
如果表格很小, 或预期结果集大小很大,就会发生 。
什么是小?如果表格小于DB_FILE_MULTIBLOCK_READ_COUNT,则几乎总会发生FTS。这种情况下,表通常可以通过一次大读取加载到内存中。这并不总是一个问题,请在解释计划中检查IO成本。
有什么大不了?如果表格很大,并且您将返回大部分内容,那么在一些大型IO调用中读取整个表格要比制作一些表格更便宜index读取然后在表格周围进行大量微小的IO调用。
从您的查询中盲目猜测(没有解释计划结果),我认为它首先会考虑索引范围扫描(通过LOG_01),然后是rowid的表访问(以获取OPERATOR_CODE,因为它不在索引中) ),但是要么它决定你的表太小,要么从那个日期范围/ structure_code返回那么多行,那么滚动表就更便宜了(用IO成本术语)。