我有一系列非常相似的查询,我针对一个包含14亿条记录(带索引)的表运行,唯一的问题是这些查询中至少有10%需要>执行时间比其他人多100倍。
我运行了一个解释计划并注意到快速查询(大约90%)Oracle正在使用索引范围扫描;在缓慢的情况下,它使用完整的索引扫描。
有没有办法强制Oracle进行索引范围扫描?
答案 0 :(得分:12)
我建议采用以下方法: -
您会注意到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作为参数。