我有一系列非常相似的查询,我针对一个包含14亿条记录(带索引)的表运行,唯一的问题是这些查询中至少有10%的执行时间比其他查询多出100倍.
我运行了一个解释计划并注意到快速查询(大约90%)Oracle正在使用索引范围扫描; 在慢速的,它使用完整的索引扫描.
有没有办法强制Oracle进行索引范围扫描?
WW.*_*WW. 12
我建议采用以下方法: -
您会注意到INDEX计划的成本更高.这就是Oracle不选择索引计划的原因.成本是甲骨文基于其统计数据和各种假设的估计.
如果计划的估计成本更高,但实际上运行得更快,那么估计是错误的.你的工作是找出估计错误的原因并纠正错误.然后,Oracle将为此声明选择正确的计划,并为其自己选择其他声明.
要弄清楚它为什么是错误的,请查看计划中预期行的数量.你可能会发现其中一个是一个数量级的.这可能是由于非均匀分布的列值,旧统计信息,彼此核心的列等.
要解决此问题,您可以让Oracle收集更好的统计信息并使用更好的启动假设进行提示.然后它将估算准确的成本并提出最快的计划.
如果您发布更多信息,我可以进一步发表评论.
要"强制"Oracle使用索引范围扫描,只需使用优化程序提示INDEX_RS_ASC.例如:
CREATE TABLE mytable (a NUMBER NOT NULL, b NUMBER NOT NULL, c CHAR(10)) NOLOGGING;
INSERT /*+ APPEND */ INTO mytable(a,b,c)
SELECT level, mod(level,100)+1, 'a' FROM dual CONNECT BY level <= 1E6;
CREATE INDEX myindex_ba ON mytable(b, a);
EXECUTE dbms_stats.gather_table_stats(NULL,'mytable');
SELECT /*+ FULL(m) */ b FROM mytable m WHERE b=10; -- full table scan
SELECT /*+ INDEX_RS_ASC(m) */ b FROM mytable m WHERE b=10; -- index range scan
SELECT /*+ INDEX_FFS(m) */ b FROM mytable m WHERE b=10; -- index fast full scan
Run Code Online (Sandbox Code Playgroud)
这是否会使您的查询实际运行得更快取决于许多因素,例如索引值的选择性或表中行的物理顺序.例如,如果将查询更改为WHERE b BETWEEN 10 AND <xxx>,则以下成本将显示在计算机的执行计划中:
b BETWEEN 10 AND 10 20 40 80
FULL 749 750 751 752
INDEX_RS_ASC 29 325 865 1943
INDEX_FFS 597 598 599 601
Run Code Online (Sandbox Code Playgroud)
如果您稍微更改查询,不仅要选择索引列b,还要选择其他非索引列,则成本会发生显着变化:
b BETWEEN 10 AND 10 20 40 80
FULL 749 750 751 754
INDEX_RS_ASC 3352 40540 108215 243563
INDEX_FFS 3352 40540 108215 243563
Run Code Online (Sandbox Code Playgroud)