为何此查询执行TABLE ACCESS FULL而非FULL INDEX SCAN?
select col2,col3 from indextest走全表扫描而非全索引扫描? 先还原下你的操作步骤:
- 创建表与复合索引:
create table indexTest( col1 NUMBER, col2 NUMBER, COL3 NUMBER); create index indexTest_INX on indexTest(col2,col3); - 验证索引结构:
analyze index indexTest_INX validate structure; - 执行查询:
select col2,col3 from indextest;
但执行计划显示TABLE ACCESS FULL,而非预期的FULL INDEX SCAN,主要有这几个常见原因:
1. 表的数据量过小,优化器选择更高效的全表扫描
Oracle的成本优化器(CBO)会计算不同执行路径的成本。如果你的indexTest表是空表或者只有几行数据,全表扫描的IO成本会比读取索引更低——毕竟索引本身也是需要磁盘IO的,小表直接扫表反而更快。
你可以插入一批测试数据(比如几千行),再重新查看执行计划,大概率会切换到全索引扫描。
2. 表的统计信息缺失或过时
CBO完全依赖准确的统计信息来判断执行路径的优劣。如果表创建后从未收集过统计信息,或者数据量发生了大幅变化但没更新统计,优化器可能无法准确评估索引的价值,默认选择全表扫描。
你可以手动收集统计信息试试:
exec dbms_stats.gather_table_stats(ownname => '你的用户名', tabname => 'INDEXTEST');
收集完成后重新执行查询,再观察执行计划的变化。
3. 优化器参数或模式影响了成本计算
有些参数会直接影响优化器对索引成本的判断,比如optimizer_index_cost_adj(默认值为100,值越高索引的相对成本越高,优化器越不容易选择索引);如果你的数据库还在使用早已废弃的RULE(基于规则的优化器)模式,也可能不会优先选择索引路径。
你可以先查看当前优化器模式:
select value from v$parameter where name = 'optimizer_mode';
如果是RULE模式,建议改成ALL_ROWS或FIRST_ROWS模式;如果是CBO模式,可以适当调低optimizer_index_cost_adj参数来降低索引的相对成本。
4. 索引可用性问题(可能性较低)
虽然你执行了analyze index ... validate structure,但还是可以确认下索引的状态:
select status from user_indexes where index_name = 'INDEXTEST_INX';
如果状态不是VALID,说明索引失效,优化器自然不会选用它。不过你已经做了结构验证,这种情况概率很低。
内容的提问来源于stack exchange,提问作者Sourav Deb

