如何强制oracle使用索引范围扫描?

时间:2010-03-18 21:58:49

标签: oracle indexing

我有一系列非常相似的查询,我针对一个包含14亿条记录(带索引)的表运行,唯一的问题是这些查询中至少有10%需要>执行时间比其他人多100倍。

我运行了一个解释计划并注意到快速查询(大约90%)Oracle正在使用索引范围扫描;在缓慢的情况下,它使用完整的索引扫描。

有没有办法强制Oracle进行索引范围扫描?

5 个答案:

答案 0 :(得分:12)

我建议采用以下方法: -

  • 在慢速陈述中获取解释计划
  • 使用INDEX提示,获取有关使用索引的解释计划

您会注意到INDEX计划的成本更高。这就是Oracle不选择索引计划的原因。成本是甲骨文基于其统计数据和各种假设的估计值。

如果计划的估计成本更高,但实际上运行得更快,那么估算是错误的。你的工作是找出估计错误的原因并纠正错误。然后,Oracle将为此声明选择正确的计划,并为其自己选择其他计划。

要找出错误原因,请查看计划中预期的行数。你可能会发现其中一个是一个数量级的。这可能是由于非均匀分布的列值,旧统计信息,彼此核对的列等等。

要解决此问题,您可以让Oracle收集更好的统计信息并使用更好的启动假设进行提示。然后它将估算准确的成本并提出最快的计划。

如果您发布更多信息,我可以进一步发表评论。

答案 1 :(得分:9)

要“强制”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

这是否会使您的查询实际运行得更快取决于许多因素,例如索引值的选择性或表中行的物理顺序。例如,如果您将查询更改为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

如果您稍微更改查询,不仅要选择索引列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

答案 2 :(得分:2)

如果您想知道优化器为什么要做出决定,您需要使用10053跟踪。

SQL> alter session set events '10053 trace name context forever, level 1';

然后运行解释计划以获取示例快速查询和示例慢查询。在用户转储目录中,您将获得详细说明CBO经历的决策树的跟踪文件。在这些文件的某处,您将找到为什么它在索引范围扫描中选择完整索引扫描的原因。

我不是说跟踪文件很容易阅读。了解它们的最佳资源是Wolfgang Breitling的优秀白皮书"A look under the hood of CBO" (PDF)

答案 3 :(得分:-1)

你可以使用oracle sql提示。您可以强制使用特定索引或排除索引 查看文档

http://psoug.org/reference/hints.html http://www.adp-gmbh.ch/ora/sql/hints/index.html

像 select / * + index(scott.emp ix_emp)* / from scott.emp emp_alias

答案 4 :(得分:-2)

我看到Oracle忽略了提示。

最近,我们的DBA使用“optimizer_index_cost_adj”并使用了索引。 这是Oracle参数,但您可以将其用作会话级别。

100是默认值,我们使用10作为参数。