CBO hints

hi, please give some links concerning CBO
documentation,experiences,...
thanks Michael

One alternative is having the hints in functions/packages in DB, if possible.

Similar Messages

  • Using CBO hints in Oracle reports 6i

    Hi everyone,
    I'm trying to add a simple hint to my a query defined in the datamodel of my report. The hint never shows up in v$sql at execution time.
    I have a stong feeling that report chops the hint out because reports thinks it's a comment like any other comment.
    Is there a way I can put hints in queries of Oracle Report 6i ????
    Best regards,
    Guillaume Goulet-Vallières

    One alternative is having the hints in functions/packages in DB, if possible.

  • How to comment my SQL in PL/SQL so that the comment carries to AWR?

    Is there anything about using comments as in /* some comment */ in a SQL statement in a PL SQL procedure and expecting that to be carried thru to AWR?
    Right now it seems my comments are not visible in the AWR history. I'm wondering if they are compiled out when they are in PL/SQL blocks or not?
    Is there a way to preserve them such that they remain without using dynamic sql?

    steffi wrote:
    Is there anything about using comments as in /* some comment */ in a SQL statement in a PL SQL procedure and expecting that to be carried thru to AWR?Comments are stripped from (static) SQL code written in PL/SQL, unless that comment is a CBO hint.
    It is a "+Good Thing+" as it reduces the memory footprint of the cursor in the shared pool. It also ensures a greater potential degree of cursor sharing as the very same SQL statement with different comments will wind up as a single re-usable cursor.
    Why exactly do you want to see comments in SQL cursors in AWR reports? This is just a high level overview - not sure what enlightenment SQL comments will bring.

  • SQL Area Usage, Performance Problem

    Hi,
    I'm a software engineer, not a DBA, with a lot of doubts about our production environment, but I think that I have found a problem at our production Database.
    At our development database when I execute the same SQL statement over than onces, I can see this behaviour (for example):
    * First execution 580 milisenconds.
    * Second execution 21 milisencons.
    As where I know, I understand that the compiled SQL statement is stored at the SQL Area, and by that reason the second execution is faster then the first one. Is that assumption correct?
    If it is correct, I have a problem on our production Database because it does not work as expected. I have done a lot of trials, and SQL statement executions do not reduce her time execution when I do consecutive SQL execution.
    Could you help me? I think that the parameter shared_pool_size value is too lower for our production server.
    Thanks in advance.
    Best Regards,
    Joan

    Just a comment about performance tuning and troubleshooting in general Joan.
    It is very dangerous to base your conclusions on observation only. Consider the following example:
    SQL> set timing on
    SQL> select count(*) from all_objects;
    COUNT(*)
    10296
    Elapsed: 00:00:18.38
    SQL>
    SQL> -- now using the magically warp speed hint
    SQL> select /*+ WARP_SPEED */ count(*) from all_objects;
    COUNT(*)
    10296
    Elapsed: 00:00:00.32
    SQL>
    From 18 seconds to less than half a second. It does look, based on pure observation of the results, that there is a WARP_SPEED hint in Oracle and it does increase performance dramatically. And we can also infer that this is an undocumented feature added by one of the Oracle kernel developers that is also a Star Trek fan. ;-)
    But if we turn on SQL tracing (as suggested), we will see that the first SELECT did a lot of physical I/O. The 2nd SELECT did the same work, but without having to do the very expensive physical I/O - as the data blocks it need to hit (again) was now in memory (inside Oracle's buffer cache).
    It had nothing to do with an invalid and non-existing CBO hint called WARP_SPEED.
    The critical bit is KNOWING exactly what you are measuring when using this type of approach. If you do not know that, you are in no position to determine a sound and valid conclusion.
    Side note on shared pool size - one of the worse mistakes can be to increase it. It can cause incredible damage to performance on an instance that deals with bindless/non-sharable SQL as the pool that Oracle needs to use to determine if a soft parse is possible gets to be huge.. without the benefit of being able to soft parse and forced to hard parse anyway. And that hard parse also now added to the size of the pool.

  • MERGE JOIN CARTESIAN

    Hi,
    I have a query which is using MERGE JOIN CARTESIAN (see step 4 and 11 in execution plan bellow) and i believe this is the culprit and query is never returning. Stats are up to date on all tables. This query involves two remote databases which are accessed using VIEWs from local database. Is there any hint which i can use here to avoid merge join Cartesian and test. Thanks. Also pasting query if any one can have any idea.
        Select  distinct
         substr(Revenue.FKDAT,5,2) || '/' || substr(Revenue.FKDAT,7,2) || '/' || substr(Revenue.FKDAT,1,4) INVOICE_DATE
        , Revenue.VBELN INVOICE_NR
        , Revenue.ARKTX CUSTDEVICE
        , (case Revenue.ZU_LOTID
        when null then hstg_partinfo_cust_dw.CUSTPARTOUT
        when '' then hstg_partinfo_cust_dw.CUSTPARTOUT
        Else
        (case decode(trim(zodss1b2.biztype),'TNR-E330-BAKE','TNR','')
        when 'TNR' then
        (case when (select CUSTPARTOUT from hstg_partinfo_cust_dw Where lotid = 'U' || substr(Revenue.ZU_LOTID,2,7) || '.' || substr(Revenue.ZU_LOTID,9) and stage = 'T998-TFIN' and rownum = 1)
         is null then (select CUSTPARTOUT from hstg_partinfo_cust_dw Where lotid = (select parentid from hstg_partinfo_cust_dw where lotid = 'U' || substr(Revenue.ZU_LOTID,2,7) || '.' || substr(Revenue.ZU_LOTID,9) and stage = 'E330-BAKE' and rownum = 1) and stage = 'T998-TFIN' and rownum = 1)
        else (select CUSTPARTOUT from hstg_partinfo_cust_dw Where lotid = 'U' || substr(Revenue.ZU_LOTID,2,7) || '.' || substr(Revenue.ZU_LOTID,9) and stage = 'T998-TFIN' and rownum = 1)
        end)
        else hstg_partinfo_cust_dw.CUSTPARTOUT
        end)
        end) CUSTPARTOUT
        , Revenue.PONUM DO_NR
        , Revenue.BSTKD PO_NR
        , Revenue.FKIMG GD_QTY
        , Revenue.zkbetr GD_PRICE
        , Revenue.NETWR GD_AMT
        , '' REJ_QTY
        , '' REJ_PRICE
        , '' REJ_AMT
        , Revenue.ZU_LOTID LOTTYPE
        ,(case Revenue.ZU_LOTID
        when null then substr(Revenue.ZU_PRTID,1,instr(Revenue.ZU_PRTID,'.') -1)
        when '' then substr(Revenue.ZU_PRTID,1,instr(Revenue.ZU_PRTID,'.') -1)
        Else
        (case decode(trim(zodss1b2.biztype),'TNR-E330-BAKE','TNR','')
        when 'TNR' then
       (case when (select substr(PARTID,1,instr(PARTID,'.') -1) from hstg_partinfo_cust_dw Where lotid = 'U' || substr(Revenue.ZU_LOTID,2,7) || '.' || substr(Revenue.ZU_LOTID,9) and stage = 'T998-TFIN' and  rownum = 1)
         is null then (select substr(PARTID,1,instr(PARTID,'.') -1) from hstg_partinfo_cust_dw Where lotid = (select parentid from hstg_partinfo_cust_dw where lotid = 'U' || substr(Revenue.ZU_LOTID,2,7) || '.' || substr(Revenue.ZU_LOTID,9) and stage = 'E330-BAKE' and rownum = 1) and stage = 'T998-TFIN' and rownum = 1)
        else (select substr(PARTID,1,instr(PARTID,'.') -1) from hstg_partinfo_cust_dw Where lotid = 'U' || substr(Revenue.ZU_LOTID,2,7) || '.' || substr(Revenue.ZU_LOTID,9) and stage = 'T998-TFIN' and rownum = 1)
        end)
        else substr(Revenue.ZU_PRTID,1,instr(Revenue.ZU_PRTID,'.') -1)
        end)
        end) PARTID
        , '' TESTER
        , substr(zodss1b2.BSTDK,5,2) || '/' || substr(zodss1b2.BSTDK,7,2) || '/' || substr(zodss1b2.BSTDK,1,4) DO_DATE
        , hstg_partinfo_cust_dw.package package
        , hstg_partinfo_cust_dw.pincount pincount
        , (select c.catg07 from ops$ods_adm.catg c where c.partid=revenue.zu_prtid) as package_size
        , (select c.catg09 from ops$ods_adm.catg c where c.partid=revenue.zu_prtid) as wafer_size
        , decode(trim(zodss1b2.biztype),'TNR-E330-BAKE','TNR','') BIZTYPE
         --from revenue, zodss1b2,dim_partinfo
         from revenue, zodss1b2,hstg_partinfo_cust_dw
         where Revenue.Remarks <> 'CANCELLED'
         and Revenue.FKART in ('ZUF2')
         and Revenue.KUNNR in ('BC1001','BC1002','BC1003')
         and Revenue.FKDAT like '201008%'
         and Revenue.FKIMG > 0
         and Revenue.kpein > 0
         and Revenue.ZU_LOTID = zodss1b2.charg
         and Revenue.MATNR = zodss1b2.matnr
         --and Revenue.ZU_PRTID = dim_partinfo.partid
         and hstg_partinfo_cust_dw.lotid='U' || substr(Revenue.ZU_LOTID,2,7) || '.' || substr(Revenue.ZU_LOTID,9)
        Union all
         Select distinct
         substr(Revenue.FKDAT,5,2) || '/' || substr(Revenue.FKDAT,7,2) || '/' || substr(Revenue.FKDAT,1,4) INVOICE_DATE
        , Revenue.VBELN INVOICE_NR
        , Revenue.ARKTX CUSTDEVICE
        , hstg_partinfo_cust_dw.CUSTPARTOUT CUSTPARTOUT
        , Revenue.PONUM DO_NR
        , Revenue.BSTKD PO_NR
        , Revenue.FKIMG GD_QTY
        , Revenue.zkbetr GD_PRICE
        , Revenue.NETWR GD_AMT
        , '' REJ_QTY
        , '' REJ_PRICE
        , '' REJ_AMT
        , Revenue.ZU_LOTID LOTTYPE
        , substr(Revenue.ZU_PRTID,1,instr(Revenue.ZU_PRTID,'.') -1) PARTID
        , '' TESTER
        , substr(zodsscrap.BSTDK,5,2) || '/' || substr(zodsscrap.BSTDK,7,2) || '/' || substr(zodsscrap.BSTDK,1,4) DO_DATE
        , hstg_partinfo_cust_dw.package package
        , hstg_partinfo_cust_dw.pincount pincount
        , (select c.catg07 from ops$ods_adm.catg c where c.partid=revenue.zu_prtid) as package_size
        , (select c.catg09 from ops$ods_adm.catg c where c.partid=revenue.zu_prtid) as wafer_size
         --from revenue, zodsscrap,dim_partinfo
         from revenue, zodsscrap,hstg_partinfo_cust_dw
         where Revenue.Remarks <> 'CANCELLED'
         and Revenue.FKART in ('ZUF2')
         and Revenue.KUNNR in ('BC1001','BC1002','BC1003')
         and Revenue.FKDAT like '201008%'
         and Revenue.FKIMG > 0
         and Revenue.kpein > 0
         and Revenue.ZU_LOTID = zodsscrap.charg
         --and Revenue.ZU_PRTID = dim_partinfo.partid
         and hstg_partinfo_cust_dw.lotid='U' || substr(Revenue.ZU_LOTID,2,7) || '.' || substr(Revenue.ZU_LOTID,9);hstg_partinfo_cust_dw is a view which is on remote database USGDWDBP and is queried using synonym in the local database.
    revenue is also a view which is in another remote database which is queried using synonym in local database.
    ODS Plan
    | Id  | Operation               |  Name       | Rows  | Bytes | Cost  | Inst   |IN-OUT|
    |   0 | SELECT STATEMENT        |             |     2 |  8532 |   999 |        |      |
    |   1 |  UNION-ALL              |             |       |       |       |        |      |
    |   2 |   SORT UNIQUE           |             |     1 |  4277 |   985 |        |      |
    |   3 |    NESTED LOOPS         |             |     1 |  4277 |   983 |        |      |
    |   4 |     MERGE JOIN CARTESIAN|             |     1 |  4107 |   980 |        |      |
    |   5 |      REMOTE             |             |     1 |  4076 |     2 | USGDW~ | R->S |
    |   6 |      BUFFER SORT        |             |   918K|    27M|   978 |        |      |
    |   7 |       TABLE ACCESS FULL | ZODSS1B2    |   918K|    27M|   978 |        |      |
    |   8 |     REMOTE              |             |     1 |   170 |     3 | SAPP0~ | R->S |
    |   9 |   SORT UNIQUE           |             |     1 |  4255 |    14 |        |      |
    |  10 |    NESTED LOOPS         |             |     1 |  4255 |    12 |        |      |
    |  11 |     MERGE JOIN CARTESIAN|             |     1 |  4096 |     9 |        |      |
    |  12 |      REMOTE             |             |     1 |  4076 |     2 | USGDW~ | R->S |
    |  13 |      BUFFER SORT        |             |  1755 | 35100 |     7 |        |      |
    |  14 |       TABLE ACCESS FULL | ZODSSCRAP   |  1755 | 35100 |     7 |        |      |
    |  15 |     REMOTE              |             |     1 |   159 |     3 | SAPP0~ | R->S |
    ---------------------------------------------------------------------------------------Thanks in advance
    Salman

    Dear Salman Qureshi,
    First of all please see Jonathan Lewis' post about the merge join cartesian;
    http://jonathanlewis.wordpress.com/2006/12/13/cartesian-merge-join/
    You may also check the Thomas Kyte's thread;
    http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:4105951726381
    You merge join cartesian cost is so low that the impact will not be that high.
    Yes, there are ways to avoid the merge join cartesian. First you have to check the where conditions. Merge join cartesian steps are happening because of the bad SQL algorithm OR sometimes Oracle needs to have a merge join cartesian. At the end, it is up to your SQL.
    After than that, you can also use the ORDERED CBO hint to avoid the merge join cartesian.
    Please add below line after the SELECT clause and see the new execution plan;
    /*+ ORDERED */I hope your problem will be fixed when you show the CBO to use the ORDERED Oracle hint.
    About the ORDERED Oracle hint, please check it out;
    http://download.oracle.com/docs/cd/B14117_01/server.101/b10752/hintsref.htm#5555
    ORDERED
    The ORDERED hint causes Oracle to join tables in the order in which they appear in the FROM clause.
    If you omit the ORDERED hint from a SQL statement performing a join, then the optimizer chooses the order in which to join the tables. You might want to use the ORDERED hint to specify a join order if you know something about the number of rows selected from each table that the optimizer does not. Such information lets you choose an inner and outer table better than the optimizer could.Hope That Helps.
    Ogan

  • Refcursor taking a lot of time to print results

    Hi Gurus,
    I have a table with name kemp with columns
    kemp_ID NOT NULL NUMBER(10)
    ACRONYM CLOB
    TERM CLOB
    DEFINITION CLOB When I do a query on table
    select * from kemp ; results are getting displayed very soon lesser than *1.5 seconds* But when I write a procedure to return the results using refcursor
    create procedure pr_retall(cv_1 in out sys_refcursor)
    as
    begin
    open cv_1 for select * from kemp ;
    end;
    set serveroutput on size unlimited;
    var x1 refcursor;
    exec pr_retall(:x1);
    print x1;This is taking around *7 seconds* for getting displayed.
    Please tell me know ways to tune it. I want to reduce the time it is consuming.
    Thanks & Regards,
    Vikas Krishna

    Vikas Krishna wrote:
    Please find the timing.
    <snipped>Using elapsed time (as you did) to measure and benchmark performance is wrong.
    Why? Because the test2 is seldom, if ever given how these tests are usually done, executed using the very same conditions that test1 was executed in.
    As conditions differ between tests, elapsed time differs. As conditions differ, you cannot compare test1 with test2. I gave an example of how wrong this is in thread {message:id=4333700} - where physical I/O slows down test1 and logical I/O speeds up test2. And how this can be used to substantiate the erroneous conclusion that the non-existing CBO hint warp_drive increased the performance of test2.
    If you want to benchmark test1 against test2, you need to know in exact detail how each test technically works.. need to know how to ensure that the commonality between the two tests remain constant for all tests and how to measure only those parts that are different between tests.
    And no, benchmarking is not that complex. It is in fact even more complex than this. Which is why it is best left to those who know how to benchmark.. on behalf of those that can find some meaning in the result of that benchmark.
    For the majority of us working and developing in the real world, benchmarking is achieving a useless answer to a meaningless question for a nonsensical issue. Utterly useless...

  • HINTS with CBO Optimizer?

    Hi Experts,
    First of all Merry Chrismas to all ...
    I am confusing in the area of HInts.. My question in that are we using any Hints when Optimizer is  CBO ?( i am using oracle 10g r2)
    bcoz some dba of my project are saying dont ever user Hints if optimizer is CBO. It will Handle the query and will give you most efficient execution plan.
    can you please guide me about this?  and my another question is that if I am writting a select statement and it involve the join of 7 tables(assume)
    then is it necessary to have the proper order of table and where clause if i am using CBO optimizer?
    Thanks in advance,
    Prashant

    1. Your DBA is right. Using Optimizer hints is the path of last resort.
    See: Ask Tom &amp;quot;Hints When to use&amp;quot;
    2. No need to worry about the order of tables, CBO is smart enough to figure that out.
    Suggest you read more about it here:
    https://blogs.oracle.com/optimizer/
    Hinting | Oracle Scratchpad

  • CBO refuses hint (sometimes)

    Sometimes, the CBO does not take hints. Can anyone explain it?
    SQL:
    SELECT * FROM v_osi_child v1 WHERE mainuuid IN (SELECT uuid FROM ot_sys_index_org v2 WHERE mainuuid IN(:p1))v_osi_child is a view which union-alls about 50 tables. ot_sys_index_org is here only used for getting some mainuuids.
    The statement itself is free of sense :)
    Explain plan:
    | Id  | Operation            | Name                    | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT     |                         |     4 | 17252 |   402K  (1)| 01:20:31 |
    |*  1 |  HASH JOIN           |                         |     4 | 17252 |   402K  (1)| 01:20:31 |
    |*  2 |   INDEX RANGE SCAN   | PK_OTSYSINDEX           |     4 |   340 |     4   (0)| 00:00:01 |
    |   3 |   VIEW               | V_OSI_CHILD             |    56M|   223G|   402K  (1)| 01:20:27 |
    |   4 |    UNION-ALL         |                         |       |       |            |          |
    |   5 |     TABLE ACCESS FULL| FL_ALLG_BENUTZERDATEN   | 16797 |  1295K|   105   (0)| 00:00:02 |
    |   6 |     TABLE ACCESS FULL| FL_BERATUNG             |    17 |  1343 |     3   (0)| 00:00:01 |
    |   7 |     TABLE ACCESS FULL| PA_KBIVBI               | 16797 |  1295K|   105   (0)| 00:00:02 |
    ...This statement needs more than 10 minutes.
    Inserting a hint:
    SELECT /*+ push_pred(v1) */ * FROM v_osi_child v1 WHERE mainuuid IN (SELECT uuid FROM ot_sys_index_org v2 WHERE mainuuid IN(:p1));Explain plan:
    | Id  | Operation                      | Name                       | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT               |                            |     4 | 17852 | 12747   (1)| 00:02:33 |
    |   1 |  NESTED LOOPS                  |                            |     4 | 17852 | 12747   (1)| 00:02:33 |
    |*  2 |   INDEX RANGE SCAN             | PK_OTSYSINDEX              |     4 |   532 |     4   (0)| 00:00:01 |
    |   3 |   VIEW                         | V_OSI_CHILD                |     1 |  4330 |  3186   (1)| 00:00:39 |
    |   4 |    UNION ALL PUSHED PREDICATE  |                            |       |       |            |          |
    |   5 |     TABLE ACCESS BY INDEX ROWID| FL_ALLG_BENUTZERDATEN      |     1 |    79 |     2   (0)| 00:00:01 |
    |*  6 |      INDEX RANGE SCAN          | OSI_FLALLGBENUTZE_MAINUUID |     1 |       |     1   (0)| 00:00:01 |
    |   7 |     TABLE ACCESS BY INDEX ROWID| FL_BERATUNG                |     1 |    79 |     2   (0)| 00:00:01 |
    |*  8 |      INDEX RANGE SCAN          | OSI_FLBERATUNG_MAINUUID    |     1 |       |     1   (0)| 00:00:01 |
    |   9 |     TABLE ACCESS BY INDEX ROWID| PA_KBIVBI                  |     1 |    79 |     2   (0)| 00:00:01 |
    |* 10 |      INDEX RANGE SCAN          | OSI_PAKBIVBI_MAINUUID      |     1 |       |     1   (0)| 00:00:01 |
    |  11 |     TABLE ACCESS BY INDEX ROWID| FL_K_AKTIVITAET            |     1 |   100 |     2   (0)| 00:00:01 |
    |* 12 |      INDEX RANGE SCAN          | OSI_FLKAKTIVITAET_MAINUUID |     1 |       |     1   (0)| 00:00:01 |
    ...Well, using the index on mainuuids is realy a good idea, if the estimated resultset of the subquery are about 4 rows.
    Costs are decreased from 402k to 12747.
    Query runs in a second.
    Now, lets modify the subquery a little bit. Again, the estimated result of the subquery are 4 rows:
    SELECT * FROM v_osi_child v1 WHERE mainuuid IN (SELECT mainuuid FROM ot_sys_index_org v2 WHERE value IN(:p1));Explain plan:
    | Id  | Operation            | Name                    | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT     |                         |     4 | 17104 |   402K  (1)| 01:20:31 |
    |*  1 |  HASH JOIN RIGHT SEMI|                         |     4 | 17104 |   402K  (1)| 01:20:31 |
    |*  2 |   INDEX RANGE SCAN   | IX_OT_SYS_INDEX01       |     4 |   192 |     5   (0)| 00:00:01 |
    |   3 |   VIEW               | V_OSI_CHILD             |    56M|   223G|   402K  (1)| 01:20:27 |
    |   4 |    UNION-ALL         |                         |       |       |            |          |
    |   5 |     TABLE ACCESS FULL| FL_ALLG_BENUTZERDATEN   | 16797 |  1295K|   105   (0)| 00:00:02 |
    |   6 |     TABLE ACCESS FULL| FL_BERATUNG             |    17 |  1343 |     3   (0)| 00:00:01 |
    |   7 |     TABLE ACCESS FULL| PA_KBIVBI               | 16797 |  1295K|   105   (0)| 00:00:02 |
    |   8 |     TABLE ACCESS FULL| FL_K_AKTIVITAET         |    26 |  2600 |     3   (0)| 00:00:01 |
    ...Well, almost the same values...
    Now, use the same hint:
    SELECT /*+ push_pred(v1) */ * FROM v_osi_child v1 WHERE mainuuid IN (SELECT mainuuid FROM ot_sys_index_org v2 WHERE value IN(:p1));Explain plan:
    | Id  | Operation            | Name                    | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT     |                         |     4 | 17104 |   402K  (1)| 01:20:31 |
    |*  1 |  HASH JOIN RIGHT SEMI|                         |     4 | 17104 |   402K  (1)| 01:20:31 |
    |*  2 |   INDEX RANGE SCAN   | IX_OT_SYS_INDEX01       |     4 |   192 |     5   (0)| 00:00:01 |
    |   3 |   VIEW               | V_OSI_CHILD             |    56M|   223G|   402K  (1)| 01:20:27 |
    |   4 |    UNION-ALL         |                         |       |       |            |          |
    |   5 |     TABLE ACCESS FULL| FL_ALLG_BENUTZERDATEN   | 16797 |  1295K|   105   (0)| 00:00:02 |
    |   6 |     TABLE ACCESS FULL| FL_BERATUNG             |    17 |  1343 |     3   (0)| 00:00:01 |
    |   7 |     TABLE ACCESS FULL| PA_KBIVBI               | 16797 |  1295K|   105   (0)| 00:00:02 |
    ...Nothing has changed.
    I can't explain it. It seems to be an oracle-bug...
    Release: 11.1.0.7.0 - 64bit Production
    OS: RHEL 5.3

    Ulrich Weiss wrote:
    All this is readable from the explain plans.I don't know the reason behind this behaviour and I don't have a 11g version to test on, but I found similar observations on a 10g database. A small yet complete reproducible test case always helps. Here is mine:
    SQL> select * from v$version ;
    BANNER
    Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
    PL/SQL Release 10.2.0.4.0 - Production
    CORE     10.2.0.4.0     Production
    TNS for Solaris: Version 10.2.0.4.0 - Production
    NLSRTL Version 10.2.0.4.0 - Production
    SQL> drop view v_t ;
    View dropped.
    SQL> drop table t1 purge ;
    Table dropped.
    SQL> drop table t purge ;
    Table dropped.
    SQL> create table t nologging as select * from all_objects ;
    Table created.
    SQL> create table t1 nologging as select * from t where rownum <= 1000 ;
    Table created.
    SQL> create or replace view v_t as
      2  select * from t where object_type = 'PACKAGE'
      3  union all
      4  select * from t where object_type = 'PACKAGE BODY' ;
    View created.
    SQL> explain plan for select * from v_t where object_id in (select object_id from t1 where owner = '
      2  SYS') ;
    Explained.
    SQL> exec dbms_stats.gather_table_stats(user, 'T') ;
    PL/SQL procedure successfully completed.
    SQL> exec dbms_stats.gather_table_stats(user, 'T1') ;
    PL/SQL procedure successfully completed.
    SQL> explain plan for select * from v_t where object_id in (select object_id from t1 where owner = 'SYS') ;
    Explained.
    SQL> select * from table(dbms_xplan.display) ;
    PLAN_TABLE_OUTPUT
    Plan hash value: 443534535
    | Id  | Operation            | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT     |      |     2 |   274 |   333   (2)| 00:00:04 |
    |*  1 |  HASH JOIN RIGHT SEMI|      |     2 |   274 |   333   (2)| 00:00:04 |
    |*  2 |   TABLE ACCESS FULL  | T1   |   893 |  8037 |     5   (0)| 00:00:01 |
    |   3 |   VIEW               | V_T  |  2055 |   256K|   327   (2)| 00:00:04 |
    |   4 |    UNION-ALL         |      |       |       |            |          |
    |*  5 |     TABLE ACCESS FULL| T    |  1067 |    97K|   164   (2)| 00:00:02 |
    |*  6 |     TABLE ACCESS FULL| T    |   988 | 92872 |   164   (2)| 00:00:02 |
    Predicate Information (identified by operation id):
       1 - access("OBJECT_ID"="OBJECT_ID")
       2 - filter("OWNER"='SYS')
       5 - filter("OBJECT_TYPE"='PACKAGE')
       6 - filter("OBJECT_TYPE"='PACKAGE BODY')
    21 rows selected.
    SQL> explain plan for select /*+ push_pred(v_t) */ * from v_t where object_id in (select object_id from t1 where owner = 'SYS') ;
    Explained.
    SQL> select * from table(dbms_xplan.display) ;
    PLAN_TABLE_OUTPUT
    Plan hash value: 443534535
    | Id  | Operation            | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT     |      |     2 |   274 |   333   (2)| 00:00:04 |
    |*  1 |  HASH JOIN RIGHT SEMI|      |     2 |   274 |   333   (2)| 00:00:04 |
    |*  2 |   TABLE ACCESS FULL  | T1   |   893 |  8037 |     5   (0)| 00:00:01 |
    |   3 |   VIEW               | V_T  |  2055 |   256K|   327   (2)| 00:00:04 |
    |   4 |    UNION-ALL         |      |       |       |            |          |
    |*  5 |     TABLE ACCESS FULL| T    |  1067 |    97K|   164   (2)| 00:00:02 |
    |*  6 |     TABLE ACCESS FULL| T    |   988 | 92872 |   164   (2)| 00:00:02 |
    Predicate Information (identified by operation id):
       1 - access("OBJECT_ID"="OBJECT_ID")
       2 - filter("OWNER"='SYS')
       5 - filter("OBJECT_TYPE"='PACKAGE')
       6 - filter("OBJECT_TYPE"='PACKAGE BODY')
    21 rows selected.
    SQL> explain plan for select v_t.* from v_t, t1 where v_t.object_id = t1.object_id and t1.owner = 'SYS' ;
    Explained.
    SQL> select * from table(dbms_xplan.display) ;
    PLAN_TABLE_OUTPUT
    Plan hash value: 2725479221
    | Id  | Operation            | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT     |      |  1834 |   245K|   333   (2)| 00:00:04 |
    |*  1 |  HASH JOIN           |      |  1834 |   245K|   333   (2)| 00:00:04 |
    |*  2 |   TABLE ACCESS FULL  | T1   |   893 |  8037 |     5   (0)| 00:00:01 |
    |   3 |   VIEW               | V_T  |  2055 |   256K|   327   (2)| 00:00:04 |
    |   4 |    UNION-ALL         |      |       |       |            |          |
    |*  5 |     TABLE ACCESS FULL| T    |  1067 |    97K|   164   (2)| 00:00:02 |
    |*  6 |     TABLE ACCESS FULL| T    |   988 | 92872 |   164   (2)| 00:00:02 |
    Predicate Information (identified by operation id):
       1 - access("V_T"."OBJECT_ID"="T1"."OBJECT_ID")
       2 - filter("T1"."OWNER"='SYS')
       5 - filter("OBJECT_TYPE"='PACKAGE')
       6 - filter("OBJECT_TYPE"='PACKAGE BODY')
    21 rows selected.
    SQL> explain plan for select /*+ push_pred(v_t) */ v_t.* from v_t, t1 where v_t.object_id = t1.object_id and t1.owner = 'SYS' ;
    Explained.
    SQL> select * from table(dbms_xplan.display) ;
    PLAN_TABLE_OUTPUT
    Plan hash value: 3926093524
    | Id  | Operation                     | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT              |      |  1834 |   263K|   292K  (2)| 00:58:28 |
    |   1 |  NESTED LOOPS                 |      |  1834 |   263K|   292K  (2)| 00:58:28 |
    |*  2 |   TABLE ACCESS FULL           | T1   |   893 | 11609 |     5   (0)| 00:00:01 |
    |   3 |   VIEW                        | V_T  |     1 |   134 |   327   (2)| 00:00:04 |
    |   4 |    UNION ALL PUSHED PREDICATE |      |       |       |            |          |
    |*  5 |     TABLE ACCESS FULL         | T    |     1 |    94 |   164   (2)| 00:00:02 |
    |*  6 |     TABLE ACCESS FULL         | T    |     1 |    94 |   164   (2)| 00:00:02 |
    Predicate Information (identified by operation id):
       2 - filter("T1"."OWNER"='SYS')
       5 - filter("OBJECT_ID"="T1"."OBJECT_ID" AND "OBJECT_TYPE"='PACKAGE')
       6 - filter("OBJECT_ID"="T1"."OBJECT_ID" AND "OBJECT_TYPE"='PACKAGE BODY')
    20 rows selected.As you can see, the PUSH_PRED hint is ignored when I use the IN clause with subquery.
    I believe this is same as what you are experiencing. However, when I change the sql to use
    a JOIN (instead of subquery), the hint is not ignored.
    p.s. I hope my JOIN query is semantically equivalent to IN..SUBQUERY.

  • CBO bug? Lack of SORT UNIQUE.

    Hi all,
    Let's consider following case:
    create table tmp as select rownum id, 0 sign from dual connect by level <= 100;
    create index tmp_i on tmp(id,sign);
    create table t as
    select mod(rownum,2) id, mod(rownum,3) val
    from dual
    connect by level <= 100000;
    begin
       dbms_stats.gather_table_stats (
          user,
          'T',
          estimate_percent   => null,
          method_opt         => 'FOR ALL COLUMNS SIZE SKEWONLY',
          cascade            => true
    end;
    begin
       dbms_stats.gather_table_stats (
          user,
          'TMP',
          estimate_percent   => null,
          method_opt         => 'FOR ALL COLUMNS SIZE SKEWONLY',
          cascade            => true
    end;
    /As you can see it scans TMP_I 50 000 times for statement with max (irrespective of distinct in subquery).
    Is there any way to enforce CBO to make SORT UNIQUE for max as well as for count so that it scans TMP_I only 3 times?
    SQL> select --+ leading(t) use_nl(t tmp)
      2  max(id)
      3  from tmp tmp
      4  where tmp.sign = 0
      5  and tmp.id in (select val from t where id = 1);
       MAX(ID)
             2
    | Id  | Operation           | Name  | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
    |   0 | SELECT STATEMENT    |       |      1 |        |      1 |00:00:00.14 |     159 |
    |   1 |  SORT AGGREGATE     |       |      1 |      1 |      1 |00:00:00.14 |     159 |
    |   2 |   NESTED LOOPS      |       |      1 |  49750 |  33333 |00:00:00.13 |     159 |
    |*  3 |    TABLE ACCESS FULL| T     |      1 |  50000 |  50000 |00:00:00.02 |     156 |
    |*  4 |    INDEX RANGE SCAN | TMP_I |  50000 |      1 |  33333 |00:00:00.07 |       3 |
    Predicate Information (identified by operation id):
       3 - filter("ID"=1)
       4 - access("TMP"."ID"="VAL" AND "TMP"."SIGN"=0)
    SQL> select --+ leading(t) use_nl(t tmp)
      2  max(id)
      3  from tmp tmp
      4  where tmp.sign = 0
      5  and tmp.id in (select distinct val from t where id = 1);
       MAX(ID)
             2
    | Id  | Operation           | Name  | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
    |   0 | SELECT STATEMENT    |       |      1 |        |      1 |00:00:00.14 |     159 |
    |   1 |  SORT AGGREGATE     |       |      1 |      1 |      1 |00:00:00.14 |     159 |
    |   2 |   NESTED LOOPS      |       |      1 |  49750 |  33333 |00:00:00.13 |     159 |
    |*  3 |    TABLE ACCESS FULL| T     |      1 |  50000 |  50000 |00:00:00.01 |     156 |
    |*  4 |    INDEX RANGE SCAN | TMP_I |  50000 |      1 |  33333 |00:00:00.07 |       3 |
    Predicate Information (identified by operation id):
       3 - filter("ID"=1)
       4 - access("TMP"."ID"="VAL" AND "TMP"."SIGN"=0)
    SQL> select --+ leading(t) use_nl(t tmp)
      2  count(id)
      3  from tmp tmp
      4  where tmp.sign = 0
      5  and tmp.id in (select val from t where id = 1);
    COUNT(ID)
             2
    | Id  | Operation            | Name  | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
    |   0 | SELECT STATEMENT     |       |      1 |        |      1 |00:00:00.03 |     158 |       |       |          |
    |   1 |  SORT AGGREGATE      |       |      1 |      1 |      1 |00:00:00.03 |     158 |       |       |          |
    |   2 |   NESTED LOOPS       |       |      1 |      3 |      2 |00:00:00.03 |     158 |       |       |          |
    |   3 |    SORT UNIQUE       |       |      1 |  50000 |      3 |00:00:00.03 |     156 |  2048 |  2048 | 2048  (0)|
    |*  4 |     TABLE ACCESS FULL| T     |      1 |  50000 |  50000 |00:00:00.01 |     156 |       |       |          |
    |*  5 |    INDEX RANGE SCAN  | TMP_I |      3 |      1 |      2 |00:00:00.01 |       2 |       |       |          |
    Predicate Information (identified by operation id):
       4 - filter("ID"=1)
       5 - access("TMP"."ID"="VAL" AND "TMP"."SIGN"=0)I can't figure out why SORT UNIQUE is absent for statement with max.
    PS. 11gR2

    Thanks for reply.
    user503699 wrote:
    I don't think it is a good idea to compare your last and first query timings as they are 2 different queries.Ok. I could compare query with max(id), sign(count(*)+1) vs max(id), sign(1). They always produce the same results so can be considered as the same.
    But I think that max(id), count(*) vs max(id) was enough to explain my point.
    user503699 wrote:
    If you are so sure of that you can write something like following :
    SQL> with data as (select /*+ materialize */ distinct val as val from t where id = 1)
    select max(id) from tmp tmp where tmp.sign = 0 and tmp.id in (select val from data) ;  2 
    I thought about that. I’m reluctant to use undocumented hints such as materialize. So folowing query has almost the best plan for my data:
    with data as (select distinct val as val from t where id = 1 and rownum > 0)
    select
    max(id)
    from tmp tmp
    where tmp.sign = 0
    and tmp.id in (select * from data);
    | Id  | Operation               | Name  | Rows  | Bytes | Cost (%CPU)| Time     |                                                                    
    |   0 | SELECT STATEMENT        |       |     1 |     8 |    50   (8)| 00:00:01 |                                                                    
    |   1 |  SORT AGGREGATE         |       |     1 |     8 |            |          |                                                                    
    |   2 |   NESTED LOOPS          |       |     3 |    24 |    50   (8)| 00:00:01 |                                                                    
    |   3 |    VIEW                 |       |     3 |     9 |    50   (8)| 00:00:01 |                                                                    
    |   4 |     HASH UNIQUE         |       |     3 |    18 |    50   (8)| 00:00:01 |                                                                    
    |   5 |      COUNT              |       |       |       |            |          |                                                                    
    |*  6 |       FILTER            |       |       |       |            |          |                                                                    
    |*  7 |        TABLE ACCESS FULL| T     | 50000 |   292K|    47   (3)| 00:00:01 |                                                                    
    |*  8 |    INDEX RANGE SCAN     | TMP_I |     1 |     5 |     0   (0)| 00:00:01 |                                                                    
    Predicate Information (identified by operation id):                                                                                                  
       6 - filter(ROWNUM>0)                                                                                                                              
       7 - filter("ID"=1)                                                                                                                                
       8 - access("TMP"."ID"="DATA"."VAL" AND "TMP"."SIGN"=0)   And changing two hidden parameters may lead to the same plan as I expect:
    alter session set "_gby_hash_aggregation_enabled" = false;
    alter session set "_simple_view_merging" = false;
    with data as (select distinct val as val from t where id = 1)
    select
    max(id)
    from tmp tmp
    where tmp.sign = 0
    and tmp.id in (select * from data);
    | Id  | Operation             | Name  | Rows  | Bytes | Cost (%CPU)| Time     |                                                                      
    |   0 | SELECT STATEMENT      |       |     1 |    18 |    50   (8)| 00:00:01 |                                                                      
    |   1 |  SORT AGGREGATE       |       |     1 |    18 |            |          |                                                                      
    |   2 |   NESTED LOOPS        |       |     3 |    54 |    50   (8)| 00:00:01 |                                                                      
    |   3 |    VIEW               |       |     3 |    39 |    50   (8)| 00:00:01 |                                                                      
    |   4 |     SORT UNIQUE       |       |     3 |    18 |    50   (8)| 00:00:01 |                                                                      
    |*  5 |      TABLE ACCESS FULL| T     | 50000 |   292K|    47   (3)| 00:00:01 |                                                                      
    |*  6 |    INDEX RANGE SCAN   | TMP_I |     1 |     5 |     0   (0)| 00:00:01 |                                                                      
    Predicate Information (identified by operation id):                                                                                                  
       5 - filter("ID"=1)                                                                                                                                
       6 - access("TMP"."ID"="DATA"."VAL" AND "TMP"."SIGN"=0)   But here I've got two additional questions:
    1. no_use_hash_aggregation can be used instead of "alter session set "_gby_hash_aggregation_enabled" = false;"
    What hint can be used instead of "alter session set "_simple_view_merging" = false;"?
    2. Is there any way to enforce CBO to use for this one
    select
    max(id)
    from tmp tmp
    where tmp.sign = 0
    and tmp.id in (select distinct val as val from t where id = 1 and rownum > 0);
    | Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time     |                                                                
    |   0 | SELECT STATEMENT            |       |     1 |     5 |     3   (0)| 00:00:01 |                                                                
    |   1 |  SORT AGGREGATE             |       |     1 |     5 |            |          |                                                                
    |   2 |   FIRST ROW                 |       |     1 |     5 |     1   (0)| 00:00:01 |                                                                
    |*  3 |    INDEX FULL SCAN (MIN/MAX)| TMP_I |     1 |     5 |     1   (0)| 00:00:01 |                                                                
    |*  4 |     FILTER                  |       |       |       |            |          |                                                                
    |   5 |      COUNT                  |       |       |       |            |          |                                                                
    |*  6 |       FILTER                |       |       |       |            |          |                                                                
    |*  7 |        TABLE ACCESS FULL    | T     |     2 |    12 |     2   (0)| 00:00:01 |                                                                
    -------------------------------------------------------------------------------------  the same plan as for this
    with data as (select distinct val as val from t where id = 1 and rownum > 0)
    select
    max(id)
    from tmp tmp
    where tmp.sign = 0
    and tmp.id in (select * from data);
    | Id  | Operation               | Name  | Rows  | Bytes | Cost (%CPU)| Time     |                                                                    
    |   0 | SELECT STATEMENT        |       |     1 |     8 |    50   (8)| 00:00:01 |                                                                    
    |   1 |  SORT AGGREGATE         |       |     1 |     8 |            |          |                                                                    
    |   2 |   NESTED LOOPS          |       |     3 |    24 |    50   (8)| 00:00:01 |                                                                    
    |   3 |    VIEW                 |       |     3 |     9 |    50   (8)| 00:00:01 |                                                                    
    |   4 |     HASH UNIQUE         |       |     3 |    18 |    50   (8)| 00:00:01 |                                                                    
    |   5 |      COUNT              |       |       |       |            |          |                                                                    
    |*  6 |       FILTER            |       |       |       |            |          |                                                                    
    |*  7 |        TABLE ACCESS FULL| T     | 50000 |   292K|    47   (3)| 00:00:01 |                                                                    
    |*  8 |    INDEX RANGE SCAN     | TMP_I |     1 |     5 |     0   (0)| 00:00:01 |                                                                    
    I don't have anything against subquery factoring clause. Just for personal interest.
    (I have read topic "Thread: Materialize a Subquery without using "with" clause"
    Materialize a Subquery without using "with" clause
    user503699 wrote:
    If you are not going to change other things (like stats collection method, table/index structures etc.) which allow optimizer to choose better plan and you know your data better, you may need to be very specific with the hints and also may have to use additional hints in order to influence optimizer decisions.
    One way to do that would be to get the base details from oracle as follows (and tweak them) :I didn't find keyword "ADVANCED" in specification for DISPLAY_CURSOR Function in documentation. Nice trick.
    But anyway outline data makes sense only in case when query already has desirable execution plan.

  • Accessing the records in ascending order using index hint

    I am getting a problem in selecting the rows using the index hint which in i want to query in the ascending order.
    for eg.
    select /*+ index(temp_itr_header,tmp_itrhdr_1#IDX2) */ person_id
    from temp_itr_header

    Oracle knows that it doesn't have to resort data if it accessed individual rows from an index with the same sort order. In other words, adding the ORDER BY clause need not cause Oracle to do any extra work. Adding the ORDER BY does guarantee that the results will be sorted and will tend to cause Oracle to use the index, assuming it can avoid the sort that way. If you don't have an ORDER BY, Oracle is free to return rows in whatever order it would like regardless of your hint.
    If you want to use the index hint, the syntax is
    SELECT /*+ INDEX(temp_itr_header <<index name>>) */Note that you do not want to have a comma in your hint. Of course, if your statistics are accurate, you shouldn't need to resort to a hint here-- the CBO should pick the most efficient path.
    Justin
    Distributed Database Consulting, Inc.
    http://www.ddbcinc.com/askDDBC

  • CBO not picking the right execution plan

    Database: Oracle 9.2.0.6 EE
    OS:Solaris 9
    I am trying to tune a query that is generated via Siebel Analytics. I am seeing a behaviour which is puzzling me but hopefully would be 'elementary' for someone like JPL.
    The query is based on a total of 7 tables. If I comment out any 2 dimension tables, the query picks up the right index on the fact table. However, the moment I add another table to the query, the plan goes awry.
    The query with 5 tables is as below:
    select count(distinct decode( T30256.HEADER_FLG , 'N' , T30256.ROW_WID ) ) as c1,
    T352305.DAY_DT as c2,
    case  when T44643.PRODUCT_CLASS_NAME = 'MobileSubscription' then T40081.ATTR15_CHAR_VAL else 'Unspecified' end  as c3,
    T352305.ROW_WID as c5
    from
                   W_PRODUCT_D T30955,
                   W_PRDATTRNM_D T44643,                         
                   W_DAY_D T352305,                 
                   W_ORDERITEM_F T30256,              
                   W_PRDATTR_D T40081                         
    where  ( T30955.ROW_WID = T44643.ROW_WID
    and T30256.LAST_UPD_DT_WID = T352305.ROW_WID
    and T30256.PROD_ATTRIB_WID = T40081.ROW_WID 
    and T30256.PROD_WID = T30955.ROW_WID
    and T30955.PROD_NAME = 'Mobile Subscription'
    and (case  when T44643.PRODUCT_CLASS_NAME = 'MobileSubscription' then T40081.ATTR15_CHAR_VAL else 'Unspecified' end  in ('BT150BB-18M', 'BT250BB-18M', 'BT50BB-18M', 'BT600BB-18M'))
    and T352305.DAY_DT between TO_DATE('2008-09-27' , 'YYYY-MM-DD') - 7 and TO_DATE('2008-09-27' , 'YYYY-MM-DD') - 1
    group by
    T352305.ROW_WID, T352305.DAY_DT,
    case  when T44643.PRODUCT_CLASS_NAME = 'MobileSubscription' then T40081.ATTR15_CHAR_VAL else 'Unspecified' end
    ;And the execution plan is as below:
    | Id  | Operation                        |  Name                | Rows  | Bytes | Cost (%CPU)|
    |   0 | SELECT STATEMENT                 |                      |   269 | 25824 | 18660   (3)|
    |   1 |  SORT GROUP BY                   |                      |   269 | 25824 | 18660   (3)|
    |   2 |   NESTED LOOPS                   |                      |   269 | 25824 | 18658   (3)|
    |   3 |    NESTED LOOPS                  |                      |  6826 |   579K|  4734   (3)|
    |   4 |     MERGE JOIN CARTESIAN         |                      |     8 |   544 |     6  (17)|
    |   5 |      NESTED LOOPS                |                      |     1 |    54 |     4  (25)|
    |   6 |       TABLE ACCESS BY INDEX ROWID| W_PRODUCT_D          |     1 |    37 |     3  (34)|
    |*  7 |        INDEX RANGE SCAN          | W_PRODUCT_D_M2       |     1 |       |     2  (50)|
    |   8 |       TABLE ACCESS BY INDEX ROWID| W_PRDATTRNM_D        |     1 |    17 |     2  (50)|
    |*  9 |        INDEX UNIQUE SCAN         | W_PRDATTRNM_D_P1     |     1 |       |            |
    |  10 |      BUFFER SORT                 |                      |     8 |   112 |     4   (0)|
    |  11 |       TABLE ACCESS BY INDEX ROWID| W_DAY_D              |     8 |   112 |     3  (34)|
    |* 12 |        INDEX RANGE SCAN          | W_DAY_D_M39          |     8 |       |     2  (50)|
    |  13 |     TABLE ACCESS BY INDEX ROWID  | W_ORDERITEM_F        |   849 | 16131 |   592   (3)|
    |* 14 |      INDEX RANGE SCAN            | W_ORDERITEM_F_INDX9  |   852 |       |     4  (25)|
    |* 15 |    INDEX RANGE SCAN              | W_PRDATTR_D_M29_T1   |     1 |     9 |     3  (34)|
    ----------------------------------------------------------------------------------------------Note how the dimension tables W_PRODUCT_D & W_DAY_D are joined using cartesian join before joining to the fact table W_ORDERITEM_F using the composite index 'W_ORDERITEM_F_INDX9'. This index consists of LAST_UPD_DT_WID, PROD_WID and ACTION_TYPE_WID, which are foreign keys to the dimension tables.
    Now if I add one more table to the query:
    select count(distinct decode( T30256.HEADER_FLG , 'N' , T30256.ROW_WID ) ) as c1,
                  T352305.DAY_DT as c2,
                   case  when T44643.PRODUCT_CLASS_NAME = 'MobileSubscription' then T40081.ATTR15_CHAR_VAL else 'Unspecified' end  as c3,
                   T30371.X_BT_DLR_GROUP as c4,
                   T352305.ROW_WID as c5
              from                W_PRODUCT_D T30955,
                   W_PRDATTRNM_D T44643,                         
                   W_DAY_D T352305,                 
                   W_ORDERITEM_F T30256,              
                   W_ORDER_D T30371,                                            
                   W_PRDATTR_D T40081                         
              where  ( T30955.ROW_WID = T44643.ROW_WID
              and T30256.LAST_UPD_DT_WID = T352305.ROW_WID
              and T30256.PROD_ATTRIB_WID = T40081.ROW_WID
              and T30256.PROD_WID = T30955.ROW_WID
              and T30256.ORDER_WID = T30371.ROW_WID
              and T30955.PROD_NAME = 'Mobile Subscription'
              and T30371.STATUS_CD = 'Complete'
              and T30371.ORDER_TYPE = 'Sales Order' 
              and (case  when T44643.PRODUCT_CLASS_NAME = 'MobileSubscription' then T40081.ATTR15_CHAR_VAL else 'Unspecified' end  in ('BT150BB-18M', 'BT250BB-18M', 'BT50BB-18M', 'BT600BB-18M'))
              and T352305.DAY_DT between TO_DATE('2008-09-27' , 'YYYY-MM-DD') - 7 and TO_DATE('2008-09-27' , 'YYYY-MM-DD') - 1
              group by T30371.X_BT_DLR_GROUP, T352305.ROW_WID, T352305.DAY_DT,
              case  when T44643.PRODUCT_CLASS_NAME = 'MobileSubscription' then T40081.ATTR15_CHAR_VAL else 'Unspecified' end;I have added a single table W_ORDER_D to the query, and the execution plan is:
    | Id  | Operation                          |  Name               | Rows  | Bytes | Cost (%CPU)|
    |   0 | SELECT STATEMENT                   |                     |    44 |  6336 | 78695   (3)|
    |   1 |  SORT GROUP BY                     |                     |    44 |  6336 | 78695   (3)|
    |   2 |   NESTED LOOPS                     |                     |    44 |  6336 | 78694   (3)|
    |   3 |    NESTED LOOPS                    |                     |   269 | 27707 | 78145   (3)|
    |*  4 |     HASH JOIN                      |                     |  6826 |   626K| 64221   (3)|
    |   5 |      TABLE ACCESS BY INDEX ROWID   | W_DAY_D             |     8 |   112 |     4  (25)|
    |*  6 |       INDEX RANGE SCAN             | W_DAY_D_M39         |     1 |       |     3  (34)|
    |   7 |      TABLE ACCESS BY INDEX ROWID   | W_ORDERITEM_F       | 86886 |  2206K| 64197   (3)|
    |   8 |       NESTED LOOPS                 |                     | 87004 |  6797K| 64200   (3)|
    |   9 |        NESTED LOOPS                |                     |     1 |    54 |     4  (25)|
    |  10 |         TABLE ACCESS BY INDEX ROWID| W_PRODUCT_D         |     1 |    37 |     3  (34)|
    |* 11 |          INDEX RANGE SCAN          | W_PRODUCT_D_M2      |     1 |       |     2  (50)|
    |  12 |         TABLE ACCESS BY INDEX ROWID| W_PRDATTRNM_D       |     1 |    17 |     2  (50)|
    |* 13 |          INDEX UNIQUE SCAN         | W_PRDATTRNM_D_P1    |     1 |       |            |
    |* 14 |        INDEX RANGE SCAN            | W_ORDERITEM_F_N6    | 86886 |       |   212  (18)|
    |* 15 |     INDEX RANGE SCAN               | W_PRDATTR_D_M29_T1  |     1 |     9 |     3  (34)|
    |* 16 |    INDEX RANGE SCAN                | W_ORDER_D_N6        |     1 |    41 |     3  (34)|
    -----------------------------------------------------------------------------------------------Now CBO doesn't choose the composite index and the cost also has increased to 78695. But if I simply add an /*+ORDERED*/ hint to the above query, so that it should join the dimension tables before joining to fact table, then the cost drops to 20913. This means that CBO is not choosing the plan with the lowest cost. I tried increasing the optimizer_max_permutations to 80000, setting session level optimizer_dynamic_sampling to 8 (just to see if it works), but no success.
    Could you please advise how to overcome this problem?
    Many thanks.

    joshic wrote:
    Database: Oracle 9.2.0.6 EE
    OS:Solaris 9
    I am trying to tune a query that is generated via Siebel Analytics. I am seeing a behaviour which is puzzling me but hopefully would be 'elementary' for someone like JPL.
    The query is based on a total of 7 tables. If I comment out any 2 dimension tables, the query picks up the right index on the fact table. However, the moment I add another table to the query, the plan goes awry.
    I have added a single table W_ORDER_D to the query, and the execution plan is:
    Now CBO doesn't choose the composite index and the cost also has increased to 78695. But if I simply add an /*+ORDERED*/ hint to the above query, so that it should join the dimension tables before joining to fact table, then the cost drops to 20913. This means that CBO is not choosing the plan with the lowest cost. I tried increasing the optimizer_max_permutations to 80000, setting session level optimizer_dynamic_sampling to 8 (just to see if it works), but no success.Back to the original question:
    * Can you force the index usage of the composite index on W_ORDERITEM_F in the second query using an INDEX hint (instead of the ORDERED hint)? If yes, what does the plan look like, particularly what cost is reported?
    * Could you post the plans including the "Predicate Information" section below the plan output?
    * What is the definition of the index W_ORDERITEM_F_N6 on W_ORDERITEM_F?
    * Are the cardinalities reported in the execution plans close to reality or way off? The best way to verify this would be to run your query with SQL tracing enabled and generate a tkprof output. If you do so please post the tkprof output here as well.
    Regards,
    Randolf
    Oracle related stuff blog:
    http://oracle-randolf.blogspot.com/
    SQLTools++ for Oracle (Open source Oracle GUI for Windows):
    http://www.sqltools-plusplus.org:7676/
    http://sourceforge.net/projects/sqlt-pp/

  • CBO not picking correct indexes or doing Full Scans

    Database version - 10.2.0.4
    OS : Solaris 5.8
    Storage: SAN
    Application : PeopleSoft Financials
    DB size : 450 gb
    DB server : 12 CPU ( 900 Mghz each ), 36 GB RAM
    ASMM - sga_target_size = 5 gb
    Locally managed tablespaces - MANUAL
    - db_file_multiblock_read_count - not set explicitly in spfile ( implicitly defaulted to 128 )
    - other optimizer related parameters are set to default
    - system_statistics - CPUSPEEDNW=456.282722513089, IOSEEKTIM =10, IOTFRSPEED=4096     
    - dictionary object system stats were last gather in Nov 09
    - stats on schema objs are gathered every night using custom script, but I have to say there are some histograms on some tables which were gathered by PS admins
    begin
    dbms_stats.gather_schema_stats(
    ownname=> 'SCHEMANM' ,
    cascade=> DBMS_STATS.AUTO_CASCADE,
    estimate_percent=> DBMS_STATS.AUTO_SAMPLE_SIZE,
    degree=> 10,
    no_invalidate=> DBMS_STATS.AUTO_INVALIDATE,
    granularity=> 'AUTO',
    method_opt=> 'FOR ALL COLUMNS SIZE 1',
    options=> 'GATHER STALE');
    end;
    Details :
    We are experiencing erratic database performance. It was upgraded from 9i to 10g along with PS software upgrade. A job that runs on one day in 12 hrs(that is high in itself) would take more than 24 hrs another day.
    We have Test and Staging envs on other servers which do not have performance issues of production magnitude. The test, staging dbs are clones of prod, created by ftp'ing files from one location to another, not sure if that makes any difference but just pointing out.
    On Prod db some symptoms which baffle me are :
    1) sql executing for over 40 minutes, check the plan and it is using an "incorrect" index, idx1. Hint sql with "correct" index, idx2, and it runs in few seconds. result set <400 rows. Cost with hint with idx2 is HIGHER. This scenario is still understandable as CBO is likely to pick a lower cost.
    - But why is there so much discrepancy in cost and response time?
    - what is influencing the CBO to pick an index which is obviously not the fastest response time?
    2) sql plan shows FTS , execution time , runs forever . But a hint with index in this case shows the cost is LOWER and response time is in seconds, so why is CBO not even evaluating this index path? Because as I understand the CBO, it will always pick the lower cost plan.
    What is influencing the CBO. Is it system stats? or any other database parameter? or the hardware ? the large SGA?? histogram ?? Stats gathering?? is there is any known issue with DBMS_STATS.AUTO_SAMPLE_SIZE and cardinaility?
    Where should I put my focus?
    What am I looking for ?
    I do have Jonathan Lewis's Cost-Based Oracle Fundamentals which I have just started so perhaps I will be enlightened but while I read it, it would be of immense help to get some advice from forum gurus.
    At this time I am not posting any exec plan or code, but I can do so if required.
    Thanks,
    JC

    Picking up just a couple of points - the ones about: why can performance change so much from one day to the next, and how can the optimizer miss a plan which (when hinted) shows a lower cost.
    NOTE: These are only suggestions that may allow you to look at critical code and recognise the pattern of behaviour
    Performance change:
    You are using "gather stale" which means tables won't get new statistics is the volume of change since the last collection is "small". But peoplesoft tables can be big, so some tables may need a lot of data to change (which might take several days or weeks) before they get new stats. The 10g optimizer is able to compare the high-values stored with the predicate values supplied in queries, and decide that since the predicate is higher than the known highest value, it should scale down its estimates of data returned. After a few days when the stats haven't changed, the optimizer suddenly gets to the point where the estimated data size is much too small and the plan changes to something that you can see is bad. The typical example here is a date column that increases with time, and a query on "recent data" - the optimizer basically says: "you want 9th Feb - the high value says 28th Jan, there's virtually no data". Keeping date and sequence-based high-values up to date is important. (See dbms_stats.set_column_stats).
    Lower cost plans available:
    Sometimes this is a bug. Sometimes it's an unlucky side effect. When a query has a large number of tables in a single query block, the optimizer can only examine a limited subset of the possible join orders (for example, a 10-table join has over 3million join orders, and the default limit is 2,000 checked). Because of this limit, Oracle starts working through a few joins orders in a methodical manner, then does a "big jump" to a different set of join orders where it checks a few more join orders, then does another "big jump". It may be that it never gets to your nice plan with the lower cost because it doesn't have time. However, by putting in the hint, you may make some of the orders the optimizer would have examined drop out of the "methodical list" - so it examines a few more in one sequence, or possibly "jumps" to a different sequence that it would not othewise have reached. (I wrote a related blog item some time ago that might make this clearer, even though it's not about exactly the same phenomenon: http://jonathanlewis.wordpress.com/2006/11/03/table-order/ ).
    Your recent comment about dynamic sampling is correct, by the way - by default (which for your version is is level 2 as a system parameter) it will only apply for tables which don't have any statistics. It's only for higher levels, or when explicitly hinted for tables, that it can apply to tables with existing statistics.
    Regards
    Jonathan Lewis
    http://jonathanlewis.wordpress.com
    http://www.jlcomp.demon.co.uk
    "Science is more than a body of knowledge; it is a way of thinking"
    Carl Sagan
    To post code, statspack/AWR report, execution plans or trace files, start and end the section with the tag {noformat}{noformat} (lowercase, curly brackets, no spaces) so that the text appears in fixed format.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

  • Degree in parallel hint is not working properly.

    Hi Experts,
    I am using the following delete statement.
    delete /*+ parallel(t,30) */ from master_header t;
    Sometimes the degree 30 is not working.
    On what basis we have to give the degree.
    Is the degree is session specific?
    To use this hint we need to follow any guidelines or check list.
    Please help me.
    Thanks.

    does your system have the capacity to have multiple parallel queries with 30 processes running concurrently? (like a Sun 6900 with 48-dual core processors or something. A little 8cpu box will not be able to handle this. That is why it is called a "hint". While you can "hint" in a query, the CBO can (and in this case will) ignore it and will reduce the parallel degree to what it sees the system can handle. It tries to keep developers from doing stupid stuff.

  • Why CBO don't use function-base index when I use like and bind variable

    Hello
    I have litle problem with function-base index and like with bind variable.
    When I use like with bind variable, the CBO don't use my function-base index.
    For example when I create table and index:
    ALTER SESSION SET NLS_SORT='BINARY_CI';
    ALTER SESSION SET NLS_COMP='LINGUISTIC';
    alter session set nls_language='ENGLISH';
    -- DROP TABLE TEST1;
    CREATE TABLE TEST1 (K1 VARCHAR2(32));
    create index test1_idx on test1(nlssort(K1,'nls_sort=BINARY_CI'));
    INSERT INTO TEST1
    SELECT OBJECT_NAME FROM ALL_OBJECTS;
    COMMIT;
    When I run:
    ALTER SESSION SET NLS_SORT='BINARY_CI';
    ALTER SESSION SET NLS_COMP='LINGUISTIC';
    SELECT * FROM TEST1 WHERE K1 = 'abcd';
    or
    SELECT * FROM TEST1 WHERE K1 LIKE 'abcd%';
    CBO use index.
    PLAN_TABLE_OUTPUT
    SQL_ID 4vrmp7cshbvqy, child number 1
    SELECT * FROM TEST1 WHERE K1 LIKE 'abcd%'
    Plan hash value: 1885706448
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    | 0 | SELECT STATEMENT | | | | 1 (100)| |
    | 1 | TABLE ACCESS BY INDEX ROWID| TEST1 | 2 | 98 | 1 (0)| 00:00:01 |
    |* 2 | INDEX RANGE SCAN | TEST1_IDX | 2 | | 1 (0)| 00:00:01 |
    Predicate Information (identified by operation id):
    2 - access("TEST1"."SYS_NC00002$">=HEXTORAW('6162636400') AND
    "TEST1"."SYS_NC00002$"<HEXTORAW('6162636500') )
    but when I run
    SELECT * FROM TEST1 WHERE K1 LIKE :1;
    CBO don't use index
    PLAN_TABLE_OUTPUT
    SQL_ID 9t461s1669gru, child number 0
    SELECT * FROM TEST1 WHERE K1 LIKE :1
    Plan hash value: 4122059633
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    | 0 | SELECT STATEMENT | | | | 89 (100)| |
    |* 1 | TABLE ACCESS FULL| TEST1 | 2 | 48 | 89 (3)| 00:00:02 |
    Predicate Information (identified by operation id):
    1 - filter("K1" LIKE :1)
    What should I change to force CBO to use index.
    I don't wont use index hint in query.
    My oracle version:
    Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
    PL/SQL Release 11.2.0.1.0 - Production
    CORE     11.2.0.1.0     Production
    TNS for 64-bit Windows: Version 11.2.0.1.0 - Production
    NLSRTL Version 11.2.0.1.0 - Production

    OK. But why if I create normal index (create index test1_idx on test1(K1)) and return to default nls settings this same query use index.
    PLAN_TABLE_OUTPUT
    SQL_ID 9t461s1669gru, child number 0
    SELECT * FROM TEST1 WHERE K1 LIKE :1
    Plan hash value: 598212486
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    | 0 | SELECT STATEMENT | | | | 1 (100)| |
    |* 1 | INDEX RANGE SCAN| TEST1_IDX | 1 | 18 | 1 (0)| 00:00:01 |
    Predicate Information (identified by operation id):
    1 - access("K1" LIKE :1)
    filter("K1" LIKE :1)
    Note
    - dynamic sampling used for this statement (level=2)
    when index is function-base (create index test1_idx on test1(nlssort(K1,'nls_sort=BINARY_CI')))
    PLAN_TABLE_OUTPUT
    SQL_ID 9t461s1669gru, child number 1
    SELECT * FROM TEST1 WHERE K1 LIKE :1
    Plan hash value: 4122059633
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    | 0 | SELECT STATEMENT | | | | 89 (100)| |
    |* 1 | TABLE ACCESS FULL| TEST1 | 3 | 54 | 89 (3)| 00:00:02 |
    Predicate Information (identified by operation id):
    1 - filter("K1" LIKE :1)
    Note
    - dynamic sampling used for this statement (level=2)
    when I create index with upper function "index test1_idx on test1(upper(K1))" the query use index
    SELECT * FROM TEST1 WHERE upper(K1) LIKE :1
    Plan hash value: 1885706448
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    | 0 | SELECT STATEMENT | | | | 1 (100)| |
    | 1 | TABLE ACCESS BY INDEX ROWID| TEST1 | 4481 | 157K| 1 (0)| 00:00:01 |
    |* 2 | INDEX RANGE SCAN | TEST1_IDX | 806 | | 1 (0)| 00:00:01 |
    Predicate Information (identified by operation id):
    2 - access("TEST1"."SYS_NC00002$" LIKE :1)
    filter("TEST1"."SYS_NC00002$" LIKE :1)
    Note
    - dynamic sampling used for this statement (level=2)

  • Strange CBO choice

    Hi guys,
    I'm runing some tests to check weather processed_flag should have NULL for already processed values or not. I thought that having a smaller index on the processed_flag column should be better.
    Check the following example:
    CREATE TABLE processed_flag_not_null AS
    SELECT LEVEL id,
           lpad('A', 10, 'A') VALUE,
           CASE
             WHEN MOD(LEVEL, 100) = 0 THEN
              0
             ELSE
              1
           END processed_flag
      FROM dual
    CONNECT BY LEVEL <= 1000000;
    CREATE INDEX IDX_PROCESSED_FLAG_NOT_NULL ON PROCESSED_FLAG_NOT_NULL (PROCESSED_FLAG);
    CREATE TABLE processed_flag_null AS
    SELECT LEVEL id,
           lpad('A', 10, 'A') VALUE,
           CASE
             WHEN MOD(LEVEL, 100) = 0 THEN
              0
           END processed_flag
      FROM dual
    CONNECT BY LEVEL <= 1000000;
    CREATE INDEX IDX_PROCESSED_FLAG_NULL ON PROCESSED_FLAG_NULL (PROCESSED_FLAG);
    BEGIN
      dbms_stats.gather_table_stats(USER, 'PROCESSED_FLAG_NOT_NULL', cascade => TRUE);
      dbms_stats.gather_table_stats(USER, 'PROCESSED_FLAG_NULL', cascade => TRUE);
    END;The first strange thing I've found was in all_tab_histograms:
    SELECT *
      FROM all_tab_histograms
    WHERE table_name IN ('PROCESSED_FLAG_NOT_NULL', 'PROCESSED_FLAG_NULL')
       AND column_name = 'PROCESSED_FLAG'
    ORDER BY 2,4;
    TABLE_NAME     COLUMN_NAME     ENDPOINT_NUMBER     ENDPOINT_VALUE
    PROCESSED_FLAG_NOT_NULL     PROCESSED_FLAG     0     0
    PROCESSED_FLAG_NOT_NULL     PROCESSED_FLAG     1     1
    PROCESSED_FLAG_NULL     PROCESSED_FLAG     0     0
    PROCESSED_FLAG_NULL     PROCESSED_FLAG     1     0Only after running queries against both tables with ("where processed_flag = 0") and gathering table stats again I get the following histograms:
    TABLE_NAME                     COLUMN_NAME     ENDPOINT_NUMBER     ENDPOINT_VALUE
    PROCESSED_FLAG_NOT_NULL     PROCESSED_FLAG     59                     0
    PROCESSED_FLAG_NOT_NULL     PROCESSED_FLAG     5598                     1
    PROCESSED_FLAG_NULL     PROCESSED_FLAG     10000                     0Can someone explain to me this behaviour?
    Now for the main question, I don't understand why the CBO chooses an Index Range Scan for the PROCESSED_FLAG_NOT_NULL table, and a Full Table Scan for the PROCESSED_FLAG_NULL:
    SQL> set timing on
    SQL> set autotrace traceonly
    SQL> SELECT *
      2    FROM processed_flag_not_null
      3   WHERE processed_flag = 0;
    10000 rows selected.
    Elapsed: 00:00:00.20
    Execution Plan
    Plan hash value: 3652560023
    | Id  | Operation                   | Name                        | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT            |                             | 10539 |   195K|    93   (0)| 00:00:02 |
    |   1 |  TABLE ACCESS BY INDEX ROWID| PROCESSED_FLAG_NOT_NULL     | 10539 |   195K|    93   (0)| 00:00:02 |
    |*  2 |   INDEX RANGE SCAN          | IDX_PROCESSED_FLAG_NOT_NULL | 10539 |  |    23   (0)| 00:00:01 |
    Predicate Information (identified by operation id):
       2 - access("PROCESSED_FLAG"=0)
    Statistics
              1  recursive calls
              0  db block gets
           4444  consistent gets
              0  physical reads
              0  redo size
         306954  bytes sent via SQL*Net to client
           7745  bytes received via SQL*Net from client
            668  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
          10000  rows processed
    SQL> SELECT *
      2    FROM processed_flag_null
      3   WHERE processed_flag = 0;
    10000 rows selected.
    Elapsed: 00:00:00.22
    Execution Plan
    Plan hash value: 1150676937
    | Id  | Operation         | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT  |                     | 10000 |   166K|   802   (2)| 00:00:10 |
    |*  1 |  TABLE ACCESS FULL| PROCESSED_FLAG_NULL | 10000 |   166K|   802   (2)| 00:00:10 |
    Predicate Information (identified by operation id):
       1 - filter("PROCESSED_FLAG"=0)
    Statistics
              1  recursive calls
              0  db block gets
           3571  consistent gets
              0  physical reads
              0  redo size
         174974  bytes sent via SQL*Net to client
           7745  bytes received via SQL*Net from client
            668  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
          10000  rows processedIf I compare both aproaches using Runstats:
    BEGIN
      runstats_pkg.rs_start;
      BEGIN
        FOR i IN 1 .. 1000
        LOOP
          FOR x IN (SELECT *
                      FROM processed_flag_not_null
                     WHERE processed_flag = 0)
          LOOP
            NULL;
          END LOOP;
        END LOOP;
      END;
      runstats_pkg.rs_middle;
      BEGIN
        FOR i IN 1 .. 1000
        LOOP
          FOR x IN (SELECT *
                      FROM processed_flag_null
                     WHERE processed_flag = 0)
          LOOP
            NULL;
          END LOOP;
        END LOOP;
      END;
      runstats_pkg.rs_stop;
    END;
    -- Output
    Run1 ran in 4295 hsecs
    Run2 ran in 5123 hsecs
    run 1 ran in 83.84% of the timeIf I compare the processed_flag_null without hints versus processed_flag_null with index hint this are the results:
    BEGIN
      runstats_pkg.rs_start;
      BEGIN
        FOR i IN 1 .. 1000
        LOOP
          FOR x IN (SELECT *
                      FROM processed_flag_null
                     WHERE processed_flag = 0)
          LOOP
            NULL;
          END LOOP;
        END LOOP;
      END;
      runstats_pkg.rs_middle;
      BEGIN
        FOR i IN 1 .. 1000
        LOOP
          FOR x IN (SELECT /*+ index(processed_flag_null IDX_PROCESSED_FLAG_NULL) */
                      FROM processed_flag_null
                     WHERE processed_flag = 0)
          LOOP
            NULL;
          END LOOP;
        END LOOP;
      END;
      runstats_pkg.rs_stop;
    END;
    -- Output
    Run1 ran in 5017 hsecs
    Run2 ran in 2212 hsecs
    run 1 ran in 226.81% of the timeAs I expected using the hint is more than twices fast of not using the index, why doesn't the CBO choose the index aproach? Can I tune the stats to give the CBO more information?
    Thanks in advance,
    Manuel Vidigal
    EDIT:
    Forgot to mention the tests were done using my laptop with Oracle 11.2.0.1.0.
    Edited by: Manuel Vidigal on 16/Set/2010 11:53

    I don't have runstats installed on my 11.2 instance so i can't reproduce your findings there, however with a simple SET TIMING ON and observing the results i get no noticeable difference between the INDEX hinted query and the not hinted query (i have an isolated sandbox where i am on the only user on the server so this is a reasonably safe method in my opinion).
    TUBBY_TUBBZ?
    BEGIN
    FOR i IN 1 .. 1000
    LOOP
       FOR x IN (SELECT *
                   FROM processed_flag_null
                  WHERE processed_flag = 0)
       LOOP
         NULL;
       END LOOP;
    END LOOP;
    END;
    12  /
    PL/SQL procedure successfully completed.
    Elapsed: 00:00:51.26
    BEGIN
    FOR i IN 1 .. 1000
    LOOP
       FOR x IN (SELECT /*+ index(processed_flag_null IDX_PROCESSED_FLAG_NULL) */
                   FROM processed_flag_null
                  WHERE processed_flag = 0)
       LOOP
         NULL;
       END LOOP;
    END LOOP;
    END;
    13  /
    PL/SQL procedure successfully completed.
    Elapsed: 00:00:50.53The results you are seeing are a consequence of the tiny nature of your table. The way you have set it up you should be seeing roughly 300 rows fitting on to a single data block (i observed 325 on my instance running on ASM) and you are only interested in returning every 100th row (again the way you set up your data) but to get every 100th row means you will have to visit EVERY block in the table.
    select
       blocks
    from dba_segments
    where segment_name = 'PROCESSED_FLAG_NULL';
    PL/SQL procedure successfully completed.
    Elapsed: 00:00:04.51
    TUBBY_TUBBZ?
                BLOCKS
                  3072
    1 row selected.
    Elapsed: 00:00:00.13Since you haven't ordered your data it's going to be inserted as the rows are generated from DUAL (so ordered by LEVEL asc). That means that you will need to get every block from the table (getting roughly 3 results per block).
    In order to visit every block in the table via an index access you cannot utilize multi-block IO, so that would be the reason the optimizer took the FULL table scan as it's choice.
    So in terms of 'fixing' this you have a couple of options.
    1) change the order of the data so it's not so evenly distributed across the blocks in the table (or possibly create this table as an index organized one so the values are sorted upon insertion and kept physically close to each other)
    2) change the size of a row such that less rows will fit on a single data block meaning that you will not actually have to return every data block for this table via your query
    lpad('A', 1000, 'A') VALUE,Would be a sufficient change to shift things in favor of index access in your example.

Maybe you are looking for

  • Mac G5i no longer recognising digital camera

    This was working fine one day and then not the other, Previously whenever I plugged in my Pentax Optio S5i via USB port it was picked up immediately and I could copy over photos. Now nothing happens I go to System Profiler and under USB it's there, s

  • Can we use free goods in MTO,thirdparty

    Hi, We cannot use free goods in MTO,thirdparty processing, do we have any sap documents supporting it,can u pls provide. Regards SR

  • Can I use a US-122MKII with Logic Pro x?

    Hi All! This is my first time on here so nice to meet you My question is: Can I use the TASCAM US-122MKII with the new Logic Pro x on an iMac? I've been using the TASCAM with my old Powerbook running Logic Pro 9 and it worked fine. Now however I can'

  • How can I turn a recorded voice into multiple voices that sound like a group of singers?

    I'm using Logic Pro 9. Could someone teach me how to turn a single recorded voice into multiple voices that sound like a group singing together by mixing or other techniques ? I don't have the luxury of a group singing together with me when I do reco

  • No recovery option is showing up

    hi im having problems with my toshiba satellite L745 and it wont load my windows 7..it always stops on black screen with flashing cursor..i keep trying the recovery option thing but no hdd recovery option is showing up..please i need some advice