How to force oracle to use index range scan?

时光怂恿深爱的人放手 提交于 2021-02-17 15:23:33

问题


I have a series of extremely similar queries that I run against a table of 1.4 billion records (with indexes), the only problem is that at least 10% of those queries take > 100x more time to execute than others.

I ran an explain plan and noticed that the for the fast queries (roughly 90%) Oracle is using an index range scan; on the slow ones, it's using a full index scan.

Is there a way to force Oracle to do an index range scan?


回答1:


To "force" Oracle to use an index range scan, simply use an optimizer hint INDEX_RS_ASC. For example:

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

Whether this will make your query actually run faster depends on many factors like the selectivity of the indexed value or the physical order of the rows in your table. For instance, if you change the query to WHERE b BETWEEN 10 AND <xxx>, the following costs appear in the execution plans on my machine:

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

If you change the query very slightly to not only select the indexed column b, but also other, non-index columns, the costs change dramatically:

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:


I suggest the following approach:-

  • Get an explain plan on the slow statement
  • Using an INDEX hint, get an explain plan on using the index

You'll notice that the cost of the INDEX plan is greater. This is why Oracle is not choosing the index plan. The cost is Oracle's estimate based on the statistics it has and various assumptions.

If the estimated cost of a plan is greater, but it actually runs quicker then the estimate is wrong. Your job is to figure out why the estimate is wrong and correct that. Then Oracle will choose the right plan for this statement and others on it's own.

To figure out why it's wrong, look at the number of expected rows in the plan. You will probably find one of these is an order of magnitude out. This might be due to non-uniformly distributed column values, old statistics, columns that corelate with each other etc.

To resolve this, you can get Oracle to collect better statistics and hint it with better starting assumptions. Then it will estimate accurate costs and come up with the fastest plan.

If you post more information I might be able to comment further.




回答3:


If you want to know why the optimizer takes the decisions it does you need to use the 10053 trace.

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

Then run explain plans for a sample fast query and a sample slow query. In the user dump directory you will get trace files detailing the decision trees which the CBO goes through. Somewhere in those files you will find the reasons why it chooses a full index scan over an index range scan.

I'm not saying the trace files are an easy read. The best resource for understanding them is Wolfgang Breitling's excellent whitepaper "A look under the hood of CBO" (PDF)




回答4:


you can use oracle sql hints. you can force to use specific index or exclude index check the documentation

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

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




回答5:


I have seen hint is ignored by Oracle.

Recently, our DBA uses "optimizer_index_cost_adj" and it utilized the index. This is Oracle parameter but you could use it as session level.

100 is default value and we used 10 as the parameter.



来源:https://stackoverflow.com/questions/2473614/how-to-force-oracle-to-use-index-range-scan

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!