How to hint hash join order on indexes ?

Hi,
in my 9.2.0.8 DB I've got query like this:
SELECT COUNT (agreementno) cnt
FROM followup
WHERE agreementno = :v001 AND actioncode = :v002 AND resultcode = :v003;
Plan
SELECT STATEMENT  CHOOSECost: 11  Bytes: 18  Cardinality: 1                      
     5 SORT AGGREGATE  Bytes: 18  Cardinality: 1                 
          4 VIEW index$_join$_001 Cost: 11  Bytes: 18  Cardinality: 1            
               3 HASH JOIN  Bytes: 18  Cardinality: 1       
                    1 INDEX RANGE SCAN NON-UNIQUE IDX_FOLLOWUP06 Cost: 13  Bytes: 18  Cardinality: 1 
                    2 INDEX RANGE SCAN UNIQUE PK_FOLLOWUP Cost: 13  Bytes: 18  Cardinality: 1  I need to change join order of indexes, so the proble one would be PK_FOLLOWUP .
Of course the best plan is index range scan on pk but during to hight CF Oracle is combining 2 indexes .
Regards.
Greg

Hmm sorry for red-herring.
I guess you could also consider hand-coding the index join, something like:
SELECT /*+ ORDERED USE_HASH (b) */
       COUNT (a.empno)
FROM  (SELECT e.empno
       FROM emp e
       WHERE e.empno > 7000) a,
      (SELECT e.empno
       FROM emp e
       WHERE e.ename LIKE 'S%') b
WHERE  a.ROWID = b.ROWID;or...
WITH e AS
     (SELECT e.empno, e.ename
        FROM emp e)
SELECT /*+ ORDERED USE_HASH (b) */
       COUNT (a.empno)
FROM   e a, e b
WHERE  b.ename LIKE 'S%'
AND    a.empno > 7000
AND    a.ROWID = b.ROWID;

Similar Messages

  • How to prevent Oracle from using an index when joining two tables ...

    How to prevent Oracle from using an index when joining two tables to get an inline view which is used in an update statement?
    O.K. I think I have to explain what I mean:
    When joining two tables which have many entries sometimes it es better not to use an index on the column used as join criteria.
    I have two tables: table A and table B.
    Table A has 4.000.000 entries and table B has 700.000 entries.
    I have a join of both tables with a numeric column as join criteria.
    There is an index on this column in table A.
    So I instead of
      where (A.col = B.col)I want to use
      where (A.col+0 = B.col)in order to prevent Oracle from using the index.
    When I use the join in a select statement it works.
    But when I use the join as inline view in an update statement I get the error ORA-01779.
    When I remove the "+0" the update statement works. (The column col is unique in table B).
    Any ideas why this happens?
    Thank you very much in advance for any help.
    Regards Hartmut

    I think you should post an properly formatted explain plan output using DBMS_XPLAN.DISPLAY including the "Predicate Information" section below the plan to provide more details regarding your query resp. update statement. Please use the \[code\] and \[code\] tags to enhance readability of the output provided:
    In SQL*Plus:
    SET LINESIZE 130
    EXPLAIN PLAN FOR <your statement>;
    SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);Usually if you're using the CBO (cost based optimizer) and have reasonable statistics gathered on the database objects used the optimizer should be able to determine if it is better to use the existing index or not.
    Things look different if you don't have statistics, you have outdated/wrong statistics or deliberately still use the RBO (rule based optimizer). In this case you would have to use other means to prevent the index usage, the most obvious would be the already mentioned NO_INDEX or FULL hint.
    But I strongly recommend to check in first place why the optimizer apparently seems to choose an inappropriate index access path.
    Regards,
    Randolf
    Oracle related stuff:
    http://oracle-randolf.blogspot.com/
    SQLTools++ for Oracle:
    http://www.sqltools-plusplus.org:7676/
    http://sourceforge.net/projects/sqlt-pp/

  • How to force Oracle using HASH JOIN

    Hi,
    I have performance issue with our SQL queries. If I use hint /*+ordered use_hash(table_name)*/ the queries run very fast as they use HASH JOIN instead of NESTED LOOPS. I have several thousands of such queries and cannot modify them in order to force Oracle to use HASH JOIN.
    I have tried to change parameters in init.ora and re-analyze the database. But the queries still use NESTED LOOPS.
    Here are some parameters in my database:
    hash_area_size=256M
    pga_aggregate_target=6G
    pgamax_size=1953125K
    pga_aggregate_target=6G
    My servers has 16G of RAM each. We are using RAC with 2 nodes.
    Please advice.
    Thx

    I donot have an answer (apart from the only answer to change each and every query to have an hint) but I have one question.
    Per session Hash area size of 256M? Is it really required? It could be a data warehouse but 256M is a bit too much for me (may be I have not worked yet on such a big environment).

  • 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

  • How do I change the order of input tables in joiner?

    I have 3 input tables in a JOINER, how can I change the order? for instance, the order now is: t1, t2, t3, for some reason, I want to change to t3, t2,t1.
    I use outer join among tables, different table order cause OWB generated different sql statement.
    Please help! Thanks.

    Unfortunately you cannot... The only way is to remove one group, then create a new one instead and re-connect the group...
    JP

  • Hash join, how to know how much of pga is using?

    Good Day everybody...
    Is there a way to know if i have enough pga for a given hash join??'
    so far i have PGA_AGGREGATE_TARGET = 200MB
    WORK AREA SIZE POLICY = AUTO
    The advisor from EM looks good, but i know that the query im interested on its expensive.
    so reworking the question...
    ¿how can i get the propper ammount of bytes needed by a given hash join?

    Its complicated - There are pages of stuff in the manual, histograms, forecast histograms.
    But I think you can get a long way with:
    SELECT name profile, cnt, decode(total, 0, 0, round(cnt*100/total)) percentage
    FROM (SELECT name, value cnt, (sum(value) over ()) total
    FROM V$SYSSTAT
    WHERE name like 'workarea exec%');
    The output of this query might look like the following:
    PROFILE CNT PERCENTAGE
    workarea executions - optimal 5395 95
    workarea executions - onepass 284 5
    workarea executions - multipass 0 0
    If all executions are optimal, who can ask for more?
    Also:
    V$PGA_TARGET_ADVICE
    This view predicts how the statistics cache hit percentage and over allocation count in V$PGASTAT will be impacted if you change the value of the initialization parameter PGA_AGGREGATE_TARGET. Example 14-8 shows a typical query of this view:
    Example 14-8 Querying V$PGA_TARGET_ADVICE
    SELECT round(PGA_TARGET_FOR_ESTIMATE/1024/1024) target_mb,
    ESTD_PGA_CACHE_HIT_PERCENTAGE cache_hit_perc,
    ESTD_OVERALLOC_COUNT
    FROM V$PGA_TARGET_ADVICE;
    The output of this query might look like the following:
    TARGET_MB CACHE_HIT_PERC ESTD_OVERALLOC_COUNT
    63 23 367
    125 24 30
    250 30 3
    375 39 0
    500 58 0
    600 59 0
    700 59 0
    800 60 0
    900 60 0
    1000 61 0
    1500 67 0
    2000 76 0
    3000 83 0
    4000 85 0
    As far as I understand if, if the overallocation count is nonzero, Oracle will override your pga_aggregate_target anyway. (Having said that, dont forget, this parameter is a target, not a hard & fast limit)

  • Query Degradation--Hash Join Degraded

    Hi All,
    I found one query degradation issue.I am on 10.2.0.3.0 (Sun OS) with optimizer_mode=ALL_ROWS.
    This is a dataware house db.
    All 3 tables involved are parition tables (with daily partitions).Partitions are created in advance and ELT jobs loads bulk data into daily partitions.
    I have checked that CBO is not using local indexes-created on them which i believe,is appropriate because when i used INDEX HINT, elapsed time increses.
    I checked giving index hint for all tables one by one but dint get any performance improvement.
    Partitions are daily loaded and after loading,partition-level stats are gathered with dbms_stats.
    We are collecting stats at partition level(granularity=>'PARTITION').Even after collecting global stats,there is no change in access pattern.Stats gather command is given below.
    PROCEDURE gather_table_part_stats(i_owner_name,i_table_name,i_part_name,i_estimate:= DBMS_STATS.AUTO_SAMPLE_SIZE, i_invalidate IN VARCHAR2 := 'Y',i_debug:= 'N')
    Only SOT_KEYMAP.IPK_SOT_KEYMAP is GLOBAL.Rest all indexes are LOCAL.
    Earlier,we were having BIND PEEKING issue,which i fixed but introducing NO_INVALIDATE=>FALSE in stats gather job.
    Here,Partition_name (20090219) is being passed through bind variables.
    SELECT a.sotrelstg_sot_ud sotcrct_sot_ud,
    b.sotkey_ud sotcrct_orig_sot_ud, a.ROWID stage_rowid
    FROM (SELECT sotrelstg_sot_ud, sotrelstg_sys_ud,
    sotrelstg_orig_sys_ord_id, sotrelstg_orig_sys_ord_vseq
    FROM sot_rel_stage
    WHERE sotrelstg_trd_date_ymd_part = '20090219'
    AND sotrelstg_crct_proc_stat_cd = 'N'
    AND sotrelstg_sot_ud NOT IN(
    SELECT sotcrct_sot_ud
    FROM sot_correct
    WHERE sotcrct_trd_date_ymd_part ='20090219')) a,
    (SELECT MAX(sotkey_ud) sotkey_ud, sotkey_sys_ud,
    sotkey_sys_ord_id, sotkey_sys_ord_vseq,
    sotkey_trd_date_ymd_part
    FROM sot_keymap
    WHERE sotkey_trd_date_ymd_part = '20090219'
    AND sotkey_iud_cd = 'I'
    --not to select logical deleted rows
    GROUP BY sotkey_trd_date_ymd_part,
    sotkey_sys_ud,
    sotkey_sys_ord_id,
    sotkey_sys_ord_vseq) b
    WHERE a.sotrelstg_sys_ud = b.sotkey_sys_ud
    AND a.sotrelstg_orig_sys_ord_id = b.sotkey_sys_ord_id
    AND NVL(a.sotrelstg_orig_sys_ord_vseq, 1) = NVL(b.sotkey_sys_ord_vseq, 1);
    During normal business hr, i found that query takes 5-7 min(which is also not acceptable), but during high load business hr,it is taking 30-50 min.
    I found that most of the time it is spending on HASH JOIN (direct path write temp).We have sufficient RAM (64 GB total/41 GB available).
    Below is the execution plan i got during normal business hr.
    | Id  | Operation                 | Name                | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |  OMem |  1Mem | Used-Mem | Used-Tmp|
    |   1 |  HASH GROUP BY            |                     |      1 |      1 |   7844K|00:05:28.78 |      16M|    217K|  35969 |       |       |          |         |
    |*  2 |   HASH JOIN               |                     |      1 |      1 |   9977K|00:04:34.02 |      16M|    202K|  20779 |   580M|    10M|  563M (1)|     650K|
    |   3 |    NESTED LOOPS ANTI      |                     |      1 |      6 |   7855K|00:01:26.41 |      16M|   1149 |      0 |       |       |          |         |
    |   4 |     PARTITION RANGE SINGLE|                     |      1 |    258K|   8183K|00:00:16.37 |   25576 |   1149 |      0 |       |       |          |         |
    |*  5 |      TABLE ACCESS FULL    | SOT_REL_STAGE       |      1 |    258K|   8183K|00:00:16.37 |   25576 |   1149 |      0 |       |       |          |         |
    |   6 |     PARTITION RANGE SINGLE|                     |   8183K|    326K|    327K|00:01:10.53 |      16M|      0 |      0 |       |       |          |         |
    |*  7 |      INDEX RANGE SCAN     | IDXL_SOTCRCT_SOT_UD |   8183K|    326K|    327K|00:00:53.37 |      16M|      0 |      0 |       |       |          |         |
    |   8 |    PARTITION RANGE SINGLE |                     |      1 |    846K|     14M|00:02:06.36 |     289K|    180K|      0 |       |       |          |         |
    |*  9 |     TABLE ACCESS FULL     | SOT_KEYMAP          |      1 |    846K|     14M|00:01:52.32 |     289K|    180K|      0 |       |       |          |         |
    I will attached the same for high load business hr once query gives results.It is still executing for last 50 mins.
    INDEX STATS (INDEXES ARE LOCAL INDEXES)
    TABLE_NAME                          INDEX_NAME                          COLUMN_NAME        COLUMN_POSITION   NUM_ROWS DISTINCT_KEYS CLUSTERING_FACTOR
    SOT_REL_STAGE                       IDXL_SOTRELSTG_SOT_UD               SOTRELSTG_SOT_UD                 1   25461560      25461560            184180
    SOT_REL_STAGE                                                           SOTRELSTG_TRD_DATE               2   25461560      25461560            184180
                                                                            _YMD_PART
    TABLE_NAME                          INDEX_NAME                          COLUMN_NAME        COLUMN_POSITION   NUM_ROWS DISTINCT_KEYS CLUSTERING_FACTOR
    SOT_KEYMAP                          IDXL_SOTKEY_ENTORDSYS_UD            SOTKEY_ENTRY_ORD_S               1 1012306940             3          38308680
                                                                            YS_UD
    SOT_KEYMAP                          IDXL_SOTKEY_HASH                    SOTKEY_HASH                      1 1049582320    1049582320        1049579520
    SOT_KEYMAP                                                              SOTKEY_TRD_DATE_YM               2 1049582320    1049582320        1049579520
                                                                            D_PART
    SOT_KEYMAP                          IDXL_SOTKEY_SOM_ORD                 SOTKEY_SOM_UD                    1 1023998560     268949136         559414840
    SOT_KEYMAP                                                              SOTKEY_SYS_ORD_ID                2 1023998560     268949136         559414840
    SOT_KEYMAP                          IPK_SOT_KEYMAP                      SOTKEY_UD                        1 1030369480    1015378900          24226580
    TABLE_NAME                          INDEX_NAME                          COLUMN_NAME        COLUMN_POSITION   NUM_ROWS DISTINCT_KEYS CLUSTERING_FACTOR
    SOT_CORRECT                         IDXL_SOTCRCT_SOT_UD                 SOTCRCT_SOT_UD                   1  412484756     412484756         411710982
    SOT_CORRECT                                                             SOTCRCT_TRD_DATE_Y               2  412484756     412484756         411710982
                                                                            MD_PART
    INDEX partiton stas (from dba_ind_partitions)
    INDEX_NAME                     PARTITION_NAME       STATUS       BLEVEL LEAF_BLOCKS DISTINCT_KEYS CLUSTERING_FACTOR   NUM_ROWS SAMPLE_SIZE LAST_ANALYZ GLO
    IDXL_SOTCRCT_SOT_UD            P20090219            USABLE            1         372        327879            216663     327879      327879 20-Feb-2009 YES
    IDXL_SOTKEY_ENTORDSYS_UD       P20090219            USABLE            2        2910             3             36618     856229      856229 19-Feb-2009 YES
    IDXL_SOTKEY_HASH               P20090219            USABLE            2        7783        853956            853914     853956      119705 19-Feb-2009 YES
    IDXL_SOTKEY_SOM_ORD            P20090219            USABLE            2        6411        531492            157147     799758      132610 19-Feb-2009 YES
    IDXL_SOTRELSTG_SOT_UD          P20090219            USABLE            2       13897       9682052             45867    9682052      794958 20-Feb-2009 YESThanks in advance.
    Bhavik Desai

    Hi Randolf,
    Thanks for the time you spent on this issue.I appreciate it.
    Please see my comments below:
    1. You've mentioned several times that you're passing the partition name as bind variable, but you're obviously testing the statement with literals rather than bind
    variables. So your tests obviously don't reflect what is going to happen in case of the actual execution. The cardinality estimates are potentially quite different when
    using bind variables for the partition key.
    Yes.I intentionaly used literals in my tests.I found couple of times that plan used by the application and plan generated by AUTOTRACE+EXPLAIN PLAN command...is same and
    caused hrly elapsed time.
    As i pointed out earlier,last month we solved couple of bind peeking issue by intproducing NO_VALIDATE=>FALSE in stats gather procedure,which we execute just after data
    load into such daily partitions and before start of jobs which executes this query.
    Execution plans From AWR (with parallelism on at table level DEGREE>1)-->This plan is one which CBO has used when degradation occured.This plan is used most of the times.
    ELAPSED_TIME_DELTA BUFFER_GETS_DELTA DISK_READS_DELTA CURSOR(SELECT*FROMTA
            1918506000          46154275              918 CURSOR STATEMENT : 4
    CURSOR STATEMENT : 4
    PLAN_TABLE_OUTPUT
    SQL_ID 39708a3azmks7
    SELECT A.SOTRELSTG_SOT_UD SOTCRCT_SOT_UD, B.SOTKEY_UD SOTCRCT_ORIG_SOT_UD, A.ROWID STAGE_ROWID FROM (SELECT SOTRELSTG_SOT_UD,
    SOTRELSTG_SYS_UD, SOTRELSTG_ORIG_SYS_ORD_ID, SOTRELSTG_ORIG_SYS_ORD_VSEQ FROM SOT_REL_STAGE WHERE SOTRELSTG_TRD_DATE_YMD_PART = :B1 AND
    SOTRELSTG_CRCT_PROC_STAT_CD = 'N' AND SOTRELSTG_SOT_UD NOT IN( SELECT SOTCRCT_SOT_UD FROM SOT_CORRECT WHERE SOTCRCT_TRD_DATE_YMD_PART =
    :B1 )) A, (SELECT MAX(SOTKEY_UD) SOTKEY_UD, SOTKEY_SYS_UD, SOTKEY_SYS_ORD_ID, SOTKEY_SYS_ORD_VSEQ, SOTKEY_TRD_DATE_YMD_PART FROM
    SOT_KEYMAP WHERE SOTKEY_TRD_DATE_YMD_PART = :B1 AND SOTKEY_IUD_CD = 'I' GROUP BY SOTKEY_TRD_DATE_YMD_PART, SOTKEY_SYS_UD,
    SOTKEY_SYS_ORD_ID, SOTKEY_SYS_ORD_VSEQ) B WHERE A.SOTRELSTG_SYS_UD = B.SOTKEY_SYS_UD AND A.SOTRELSTG_ORIG_SYS_ORD_ID =
    B.SOTKEY_SYS_ORD_ID AND NVL(A.SOTRELSTG_ORIG_SYS_ORD_VSEQ, 1) = NVL(B.SOTKEY_SYS_ORD_VSEQ, 1)
    Plan hash value: 1213870831
    | Id  | Operation                     | Name                | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |    TQ  |IN-OUT| PQ Distrib |
    |   0 | SELECT STATEMENT              |                     |       |       | 19655 (100)|          |       |       |        |      |            |
    |   1 |  PX COORDINATOR               |                     |       |       |            |          |       |       |        |      |            |
    |   2 |   PX SEND QC (RANDOM)         | :TQ10003            |     1 |   116 | 19655   (1)| 00:05:54 |       |       |  Q1,03 | P->S | QC (RAND)  |
    |   3 |    HASH GROUP BY              |                     |     1 |   116 | 19655   (1)| 00:05:54 |       |       |  Q1,03 | PCWP |            |
    |   4 |     PX RECEIVE                |                     |     1 |   116 | 19655   (1)| 00:05:54 |       |       |  Q1,03 | PCWP |            |
    |   5 |      PX SEND HASH             | :TQ10002            |     1 |   116 | 19655   (1)| 00:05:54 |       |       |  Q1,02 | P->P | HASH       |
    |   6 |       HASH GROUP BY           |                     |     1 |   116 | 19655   (1)| 00:05:54 |       |       |  Q1,02 | PCWP |            |
    |   7 |        NESTED LOOPS ANTI      |                     |     1 |   116 | 19654   (1)| 00:05:54 |       |       |  Q1,02 | PCWP |            |
    |   8 |         HASH JOIN             |                     |     1 |   102 | 19654   (1)| 00:05:54 |       |       |  Q1,02 | PCWP |            |
    |   9 |          PX JOIN FILTER CREATE| :BF0000             |    13M|   664M|  2427   (3)| 00:00:44 |       |       |  Q1,02 | PCWP |            |
    |  10 |           PX RECEIVE          |                     |    13M|   664M|  2427   (3)| 00:00:44 |       |       |  Q1,02 | PCWP |            |
    |  11 |            PX SEND HASH       | :TQ10000            |    13M|   664M|  2427   (3)| 00:00:44 |       |       |  Q1,00 | P->P | HASH       |
    |  12 |             PX BLOCK ITERATOR |                     |    13M|   664M|  2427   (3)| 00:00:44 |   KEY |   KEY |  Q1,00 | PCWC |            |
    |  13 |              TABLE ACCESS FULL| SOT_REL_STAGE       |    13M|   664M|  2427   (3)| 00:00:44 |   KEY |   KEY |  Q1,00 | PCWP |            |
    |  14 |          PX RECEIVE           |                     |    27M|  1270M| 17209   (1)| 00:05:10 |       |       |  Q1,02 | PCWP |            |
    |  15 |           PX SEND HASH        | :TQ10001            |    27M|  1270M| 17209   (1)| 00:05:10 |       |       |  Q1,01 | P->P | HASH       |
    |  16 |            PX JOIN FILTER USE | :BF0000             |    27M|  1270M| 17209   (1)| 00:05:10 |       |       |  Q1,01 | PCWP |            |
    |  17 |             PX BLOCK ITERATOR |                     |    27M|  1270M| 17209   (1)| 00:05:10 |   KEY |   KEY |  Q1,01 | PCWC |            |
    |  18 |              TABLE ACCESS FULL| SOT_KEYMAP          |    27M|  1270M| 17209   (1)| 00:05:10 |   KEY |   KEY |  Q1,01 | PCWP |            |
    |  19 |         PARTITION RANGE SINGLE|                     | 16185 |   221K|     0   (0)|          |   KEY |   KEY |  Q1,02 | PCWP |            |
    |  20 |          INDEX RANGE SCAN     | IDXL_SOTCRCT_SOT_UD | 16185 |   221K|     0   (0)|          |   KEY |   KEY |  Q1,02 | PCWP |            |
    Other Execution plan from AWR
    ELAPSED_TIME_DELTA BUFFER_GETS_DELTA DISK_READS_DELTA CURSOR(SELECT*FROMTA
            1053251381                 0             2925 CURSOR STATEMENT : 4
    CURSOR STATEMENT : 4
    PLAN_TABLE_OUTPUT
    SQL_ID 39708a3azmks7
    SELECT A.SOTRELSTG_SOT_UD SOTCRCT_SOT_UD, B.SOTKEY_UD SOTCRCT_ORIG_SOT_UD, A.ROWID STAGE_ROWID FROM (SELECT SOTRELSTG_SOT_UD,
    SOTRELSTG_SYS_UD, SOTRELSTG_ORIG_SYS_ORD_ID, SOTRELSTG_ORIG_SYS_ORD_VSEQ FROM SOT_REL_STAGE WHERE SOTRELSTG_TRD_DATE_YMD_PART = :B1 AND
    SOTRELSTG_CRCT_PROC_STAT_CD = 'N' AND SOTRELSTG_SOT_UD NOT IN( SELECT SOTCRCT_SOT_UD FROM SOT_CORRECT WHERE SOTCRCT_TRD_DATE_YMD_PART =
    :B1 )) A, (SELECT MAX(SOTKEY_UD) SOTKEY_UD, SOTKEY_SYS_UD, SOTKEY_SYS_ORD_ID, SOTKEY_SYS_ORD_VSEQ, SOTKEY_TRD_DATE_YMD_PART FROM
    SOT_KEYMAP WHERE SOTKEY_TRD_DATE_YMD_PART = :B1 AND SOTKEY_IUD_CD = 'I' GROUP BY SOTKEY_TRD_DATE_YMD_PART, SOTKEY_SYS_UD,
    SOTKEY_SYS_ORD_ID, SOTKEY_SYS_ORD_VSEQ) B WHERE A.SOTRELSTG_SYS_UD = B.SOTKEY_SYS_UD AND A.SOTRELSTG_ORIG_SYS_ORD_ID =
    B.SOTKEY_SYS_ORD_ID AND NVL(A.SOTRELSTG_ORIG_SYS_ORD_VSEQ, 1) = NVL(B.SOTKEY_SYS_ORD_VSEQ, 1)
    Plan hash value: 3434900850
    | Id  | Operation                     | Name                | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |    TQ  |IN-OUT| PQ Distrib |
    |   0 | SELECT STATEMENT              |                     |       |       |  1830 (100)|          |       |       |        |      |            |
    |   1 |  PX COORDINATOR               |                     |       |       |            |          |       |       |        |      |            |
    |   2 |   PX SEND QC (RANDOM)         | :TQ10003            |     1 |   131 |  1830   (2)| 00:00:33 |       |       |  Q1,03 | P->S | QC (RAND)  |
    |   3 |    HASH GROUP BY              |                     |     1 |   131 |  1830   (2)| 00:00:33 |       |       |  Q1,03 | PCWP |            |
    |   4 |     PX RECEIVE                |                     |     1 |   131 |  1830   (2)| 00:00:33 |       |       |  Q1,03 | PCWP |            |
    |   5 |      PX SEND HASH             | :TQ10002            |     1 |   131 |  1830   (2)| 00:00:33 |       |       |  Q1,02 | P->P | HASH       |
    |   6 |       HASH GROUP BY           |                     |     1 |   131 |  1830   (2)| 00:00:33 |       |       |  Q1,02 | PCWP |            |
    |   7 |        NESTED LOOPS ANTI      |                     |     1 |   131 |  1829   (2)| 00:00:33 |       |       |  Q1,02 | PCWP |            |
    |   8 |         HASH JOIN             |                     |     1 |   117 |  1829   (2)| 00:00:33 |       |       |  Q1,02 | PCWP |            |
    |   9 |          PX JOIN FILTER CREATE| :BF0000             |  1010K|    50M|   694   (1)| 00:00:13 |       |       |  Q1,02 | PCWP |            |
    |  10 |           PX RECEIVE          |                     |  1010K|    50M|   694   (1)| 00:00:13 |       |       |  Q1,02 | PCWP |            |
    |  11 |            PX SEND HASH       | :TQ10000            |  1010K|    50M|   694   (1)| 00:00:13 |       |       |  Q1,00 | P->P | HASH       |
    |  12 |             PX BLOCK ITERATOR |                     |  1010K|    50M|   694   (1)| 00:00:13 |   KEY |   KEY |  Q1,00 | PCWC |            |
    |  13 |              TABLE ACCESS FULL| SOT_KEYMAP          |  1010K|    50M|   694   (1)| 00:00:13 |   KEY |   KEY |  Q1,00 | PCWP |            |
    |  14 |          PX RECEIVE           |                     |    11M|   688M|  1129   (3)| 00:00:21 |       |       |  Q1,02 | PCWP |            |
    |  15 |           PX SEND HASH        | :TQ10001            |    11M|   688M|  1129   (3)| 00:00:21 |       |       |  Q1,01 | P->P | HASH       |
    |  16 |            PX JOIN FILTER USE | :BF0000             |    11M|   688M|  1129   (3)| 00:00:21 |       |       |  Q1,01 | PCWP |            |
    |  17 |             PX BLOCK ITERATOR |                     |    11M|   688M|  1129   (3)| 00:00:21 |   KEY |   KEY |  Q1,01 | PCWC |            |
    |  18 |              TABLE ACCESS FULL| SOT_REL_STAGE       |    11M|   688M|  1129   (3)| 00:00:21 |   KEY |   KEY |  Q1,01 | PCWP |            |
    |  19 |         PARTITION RANGE SINGLE|                     |  5209 | 72926 |     0   (0)|          |   KEY |   KEY |  Q1,02 | PCWP |            |
    |  20 |          INDEX RANGE SCAN     | IDXL_SOTCRCT_SOT_UD |  5209 | 72926 |     0   (0)|          |   KEY |   KEY |  Q1,02 | PCWP |            |
    EXECUTION PLAN AFTER SETTING DEGREE=1 (It was also degraded)
    | Id  | Operation                 | Name                | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |
    |   0 | SELECT STATEMENT          |                     |     1 |   129 |       | 42336   (2)| 00:12:43 |       |       |
    |   1 |  HASH GROUP BY            |                     |     1 |   129 |       | 42336   (2)| 00:12:43 |       |       |
    |   2 |   NESTED LOOPS ANTI       |                     |     1 |   129 |       | 42335   (2)| 00:12:43 |       |       |
    |*  3 |    HASH JOIN              |                     |     1 |   115 |    51M| 42334   (2)| 00:12:43 |       |       |
    |   4 |     PARTITION RANGE SINGLE|                     |   846K|    41M|       |  8241   (1)| 00:02:29 |    81 |    81 |
    |*  5 |      TABLE ACCESS FULL    | SOT_KEYMAP          |   846K|    41M|       |  8241   (1)| 00:02:29 |    81 |    81 |
    |   6 |     PARTITION RANGE SINGLE|                     |  8161K|   490M|       | 12664   (3)| 00:03:48 |    81 |    81 |
    |*  7 |      TABLE ACCESS FULL    | SOT_REL_STAGE       |  8161K|   490M|       | 12664   (3)| 00:03:48 |    81 |    81 |
    |   8 |    PARTITION RANGE SINGLE |                     |  6525K|    87M|       |     1   (0)| 00:00:01 |    81 |    81 |
    |*  9 |     INDEX RANGE SCAN      | IDXL_SOTCRCT_SOT_UD |  6525K|    87M|       |     1   (0)| 00:00:01 |    81 |    81 |
    Predicate Information (identified by operation id):
       3 - access("SOTRELSTG_SYS_UD"="SOTKEY_SYS_UD" AND "SOTRELSTG_ORIG_SYS_ORD_ID"="SOTKEY_SYS_ORD_ID" AND
                  NVL("SOTRELSTG_ORIG_SYS_ORD_VSEQ",1)=NVL("SOTKEY_SYS_ORD_VSEQ",1))
       5 - filter("SOTKEY_TRD_DATE_YMD_PART"=20090219 AND "SOTKEY_IUD_CD"='I')
       7 - filter("SOTRELSTG_CRCT_PROC_STAT_CD"='N' AND "SOTRELSTG_TRD_DATE_YMD_PART"=20090219)
       9 - access("SOTRELSTG_SOT_UD"="SOTCRCT_SOT_UD" AND "SOTCRCT_TRD_DATE_YMD_PART"=20090219)2. Why are you passing the partition name as bind variable? A statement executing 5 mins. best, > 2 hours worst obviously doesn't suffer from hard parsing issues and
    doesn't need to (shouldn't) share execution plans therefore. So I strongly suggest to use literals instead of bind variables. This also solves any potential issues caused
    by bind variable peeking.
    This is a custom application which uses bind variables to extract data from daily partitions.So,daily automated data extract from daily paritions after load and ELT process.
    Here,Value of bind variable is being passed through a procedure parameter.It would be bit difficult to use literals in such application.
    3. All your posted plans suffer from bad cardinality estimates. The NO_MERGE hint suggested by Timur only caused a (significant) damage limitation by obviously reducing
    the row source size by the group by operation before joining, but still the optimizer is way off, apart from the obviously wrong join order (larger row set first) in
    particular the NESTED LOOP operation is causing the main troubles due to excessive logical I/O, as already pointed out by Timur.
    Can i ask for alternatives to NESTED LOOP?
    4. Your PLAN_TABLE seems to be old (you should see a corresponding note at the bottom of the DBMS_XPLAN.DISPLAY output), because none of the operations have a
    filter/access predicate information attached. Since your main issue are the bad cardinality estimates, I strongly suggest to drop any existing PLAN_TABLEs in any non-Oracle
    owned schemas because 10g already provides one in the SYS schema (GTT PLAN_TABLE$) exposed via a public synonym, so that the EXPLAIN PLAN information provides the
    "Predicate Information" section below the plan covering the "Filter/Access" predicates.
    Please post a revised explain plan output including this crucial information so that we get a clue why the cardinality estimates are way off.
    I have dropped the old plan.Got above execution plan(listed above in first point) with PREDICATE information.
    "As already mentioned the usage of bind variables for the partition name makes this issue potentially worse."
    Is there any workaround without replacing bind variable.I am on 10g so 11g's feature will not help !!!
    How are you gathering the statistics daily, can you post the exact command(s) used?
    gather_table_part_stats(i_owner_name,i_table_name,i_part_name,i_estimate:= DBMS_STATS.AUTO_SAMPLE_SIZE, i_invalidate IN VARCHAR2 := 'Y',i_debug:= 'N')
    Thanks & Regards,
    Bhavik Desai

  • How can we specify the order of the predicates execution?

    I am going to write the following query
    select answer, answer_id from surveys s join answers a on s.survey_id = a.survey_seq_id
    where question_uid = 206400374 and insertdate = to_date('31/12/2012') and answer > 0;However, when I look at the execution plan, I see that the last predicate (to_number(answer) > 0) has been executed the first. Henceforth, it checks many rows first. Normally, 75 rows belong to 31/12/2012 as you see from the following. Can I specify the execution order?
    select count(*) from surveys s join answers a on s.survey_id = a.survey_seq_id
    where question_uid = 206400374 and insertdate = to_date('31/12/2012');
    COUNT(*)
    75If so, how? Because, the type of answer is varchar2 and some of answers contain text characters such as 'Yes' or 'No'. Therefore, before 31/12/2012 some answers contain 'Yes' or 'No'. However in 31/12/2012 all answers are numeric.
    Plan hash value: 3217836037
    | Id  | Operation          | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT   |         |     2 |    68 |  9401   (1)| 00:01:53 |
    |*  1 |  HASH JOIN         |         |     2 |    68 |  9401   (1)| 00:01:53 |
    |*  2 |   TABLE ACCESS FULL| SURVEYS |     2 |    26 |   239   (1)| 00:00:03 |
    |*  3 |   TABLE ACCESS FULL| ANSWERS |   337 |  7077 |  9162   (1)| 00:01:50 |
    Predicate Information (identified by operation id):
       1 - access("S"."SURVEY_ID"="A"."SURVEY_SEQ_ID")
       2 - filter("S"."INSERTDATE"=TO_DATE(' 2012-12-31 00:00:00',
                  'syyyy-mm-dd hh24:mi:ss'))
       3 - filter("A"."QUESTION_UID"=206400374 AND
                  TO_NUMBER("A"."ANSWER")>0)
    select distinct answer from surveys s join answers a on s.survey_id = a.survey_seq_id
    where question_uid = 206400374 and insertdate = to_date('31/12/2012');
    ANSWER
    1
    3
    0
    2And, also I can execute the following query without any error
    select to_number(answer) from surveys s join answers a on s.survey_id = a.survey_seq_id
    where question_uid = 206400374 and insertdate = to_date('31/12/2012');

    In answer to your original question:
    970992 wrote:
    However, when I look at the execution plan, I see that the last predicate (to_number(answer) > 0) has been executed the first. Henceforth, it checks many rows first. Normally, 75 rows belong to 31/12/2012 as you see from the following. Can I specify the execution order?According to the execution plan, it will do a full scan of surveys using the predicate on insertdate to build the (presumably in-memory) hash table (hash based on survey_id) to do the joins (Step 2). Then, it does a full scan of the answers table using the question_uid and answer predicates (Step 3). For each row it finds that matches those predicate, it will prpobe the hash table created in step 2 using the hashed value of survey_seq_id. So, it is doing the insertdate predicate first.
    In answer to your last post
    970992 wrote:
    >
    First of all i would get rid of the implizit type conversion:
    TO_NUMBER("A"."ANSWER")>0)it is not implicit conversion, I reckon it is explicit type conversion, isnt it?
    No, it is an implicit type conversion. Your code says answer > 0, since the answer column is a varchar2 column, Oracle implicitly converts the answer column to a number to compare against the number on the right side of the comparison. Note that if something like 'A' ever becomes a valid answer, then this query will fail with ORA-01722: invalid number.
    >
    >
    Obviously "A"."ANSWER" is not a number colmun, problably varchar, so use something like
    A.ANSWER != "0"
    or
    A.ANSWER > "0"Yes answer column is varchar2 but can you type A.ANSWER > "0" as a predicate? I mean, you can not varchar > varchar, can you?
    Of course you can use inequality predicates on a varcahr column. Is the string A greater than the string B?
    Based on the explain plan, your statistics might be a little off, not hugely so. The esitmates are at least in the right order of magnitude based on what you have posted so far.
    What indexes, if any, are available on the two tables?
    John

  • Why optimizer prefers nested loop over hash join?

    What do I look for if I want to find out why the server prefers a nested loop over hash join?
    The server is 10.2.0.4.0.
    The query is:
    SELECT p.*
        FROM t1 p, t2 d
        WHERE d.emplid = p.id_psoft
          AND p.flag_processed = 'N'
          AND p.desc_pool = :b1
          AND NOT d.name LIKE '%DUPLICATE%'
          AND ROWNUM < 2tkprof output is:
    Production
    call     count       cpu    elapsed       disk      query    current        rows
    Parse        1      0.01       0.00          0          0          4           0
    Execute      1      0.00       0.01          0          4          0           0
    Fetch        1    228.83     223.48          0    4264533          0           1
    total        3    228.84     223.50          0    4264537          4           1
    Misses in library cache during parse: 1
    Optimizer mode: ALL_ROWS
    Parsing user id: 108  (SANJEEV)
    Rows     Row Source Operation
          1  COUNT STOPKEY (cr=4264533 pr=0 pw=0 time=223484076 us)
          1   NESTED LOOPS  (cr=4264533 pr=0 pw=0 time=223484031 us)
      10401    TABLE ACCESS FULL T1 (cr=192 pr=0 pw=0 time=228969 us)
          1    TABLE ACCESS FULL T2 (cr=4264341 pr=0 pw=0 time=223182508 us)Development
    call     count       cpu    elapsed       disk      query    current        rows
    Parse        1      0.01       0.00          0          0          0           0
    Execute      1      0.00       0.01          0          4          0           0
    Fetch        1      0.05       0.03          0        512          0           1
    total        3      0.06       0.06          0        516          0           1
    Misses in library cache during parse: 1
    Optimizer mode: ALL_ROWS
    Parsing user id: 113  (SANJEEV)
    Rows     Row Source Operation
          1  COUNT STOPKEY (cr=512 pr=0 pw=0 time=38876 us)
          1   HASH JOIN  (cr=512 pr=0 pw=0 time=38846 us)
         51    TABLE ACCESS FULL T2 (cr=492 pr=0 pw=0 time=30230 us)
        861    TABLE ACCESS FULL T1 (cr=20 pr=0 pw=0 time=2746 us)

    sanjeevchauhan wrote:
    What do I look for if I want to find out why the server prefers a nested loop over hash join?
    The server is 10.2.0.4.0.
    The query is:
    SELECT p.*
    FROM t1 p, t2 d
    WHERE d.emplid = p.id_psoft
    AND p.flag_processed = 'N'
    AND p.desc_pool = :b1
    AND NOT d.name LIKE '%DUPLICATE%'
    AND ROWNUM < 2
    You've got already some suggestions, but the most straightforward way is to run the unhinted statement in both environments and then force the join and access methods you would like to see using hints, in your case probably "USE_HASH(P D)" in your production environment and "FULL(P) FULL(D) USE_NL(P D)" in your development environment should be sufficient to see the costs and estimates returned by the optimizer when using the alternate access and join patterns.
    This give you a first indication why the optimizer thinks that the chosen access path seems to be cheaper than the obviously less efficient plan selected in production.
    As already mentioned by Hemant using bind variables complicates things a bit since EXPLAIN PLAN is not reliable due to bind variable peeking performed when executing the statement, but not when explaining.
    Since you're already on 10g you can get the actual execution plan used for all four variants using DBMS_XPLAN.DISPLAY_CURSOR which tells you more than the TKPROF output in the "Row Source Operation" section regarding the estimates and costs assigned.
    Of course the result of your whole exercise might be highly dependent on the actual bind variable value used.
    By the way, your statement is questionable in principle since you're querying for the first row of an indeterministic result set. It's not deterministic since you've defined no particular order so depending on the way Oracle executes the statement and the physical storage of your data this query might return different results on different runs.
    This is either an indication of a bad design (If the query is supposed to return exactly one row then you don't need the ROWNUM restriction) or an incorrect attempt of a Top 1 query which requires you to specify somehow an order, either by adding a ORDER BY to the statement and wrapping it into an inline view, or e.g. using some analytic functions that allow you specify a RANK by a defined ORDER.
    This is an example of how a deterministic Top N query could look like:
    SELECT
    FROM
    SELECT p.*
        FROM t1 p, t2 d
        WHERE d.emplid = p.id_psoft
          AND p.flag_processed = 'N'
          AND p.desc_pool = :b1
          AND NOT d.name LIKE '%DUPLICATE%'
    ORDER BY <order_criteria>
    WHERE ROWNUM <= 1;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/

  • Seeking advice on a heavy hash join

    We have to self-join a 190 million row table 160 times. On our production 9i database we give "RULE" hint and it finishes in about an hour using nested loop join, On our test 10g database, since "RULE" is not available any more. The optimiser chooses to use hash join (160 levels). And query never finishes in a reasonable time. We have gradually increase the hash_area_size from 8M to 512M, thinking that will help. But apparently it does not. Can anyone provide suggestions? Thanks.

    There is an approach using Analytics Functions that may be useful here. The idea is to get all the data values required with 1 reference to Tab2 rather than 160, and let Analytics do the work of building the result set.
    The goal here is to 'never do multiple references to the same table where 1 reference can suffice (usually with the aid of Analytics)'.
    There are 2 variations depending on whether the ID values here (0,10,20,30,...) always follow an ascending pattern or if they don't. The second example is more generic and will also cover the ascending case.
    name ID val ID val ID val ID val ID val
    name1 0 1 10 1 20 1 30 1 40 1
    -- Performance Summary - This demo used a max value of 1600 vs 15000
    for a net number of rows of 2.5 million versus 225 million.
    Any of the test views ( replacing 5,10, or 160 tab2 references) using the Analytics function used at most 4099 consistent gets. The original approach used 20553 consistent gets for 5 tab2 references, 41016 consistent gets for 10 tab2 references. This was in 10g, doing the hash join. I did try alter session set optimizer_mode = rule (just for test purposes) and that resulted in 46462 consistent gets for the 10 tab2 reference view while it did a merge join operation.
    Autotrace for the Analytics version to replace the original 160 table sql.
    JT(147)@JTDB10G>select * from analytics_2_joins;
    1600 rows selected.
    Statistics
    0 recursive calls
    0 db block gets
    4099 consistent gets
    3710 physical reads
    0 redo size
    1112904 bytes sent via SQL*Net to client
    1250 bytes received via SQL*Net from client
    81 SQL*Net roundtrips to/from client
    2 sorts (memory)
    0 sorts (disk)
    1600 rows processed
    -- Minimal examples:
    --As always, test thoroughly before using in production.
    select name,
         id0, value value0,
         id1, value value1,
         id2, value value2,
         id3, value value3,
         id4, value value4
    from ( select name, id, value,
         lead(id,0 ) over(partition by name, value order by rn ) id0 ,
         lead(id,1 ) over(partition by name, value order by rn ) id1 ,
         lead(id,2 ) over(partition by name, value order by rn ) id2 ,
         lead(id,3 ) over(partition by name, value order by rn ) id3 ,
         lead(id,4 ) over(partition by name, value order by rn ) id4 ,
    rn
    from( select tab1.name, i0.id, i0.tab1value value,
    (row_number() over (partition by tab1value order by i0.id )) -1 rn
    from tab1, tab2 i0 where tab1.name='name1' and i0.tab1value=tab1.value
    and i0.id in (0,10,20,30,40)
    )) where rn = 0;
    -- execute a verions of the smaller analytics approch with bind variables
    -- referencing the binds within the numbered in-line view is needed only if
    -- the id0, id1, id2 values do not follow the ascending pattern shown in the
    -- example. This will handle case where id0 = 30, id2 =20, id4 = 40 , etc.
    variable l_id0 number;
    variable l_id1 number;
    variable l_id2 number;
    variable l_id3 number;
    variable l_id4 number;
    exec :l_id1 := 0;
    exec :l_id3 := 10;
    exec :l_id2 := 20;
    exec :l_id0 := 30;
    exec :l_id4 := 40;
    select name, bind_rn,
         id0, value value0,
         id1, value value1,
         id2, value value2,
         id3, value value3,
         id4, value value4
    from ( select name, id, value,
         lead(id,0 ) over(partition by name, value order by bind_rn ) id0 ,
         lead(id,1 ) over(partition by name, value order by bind_rn ) id1 ,
         lead(id,2 ) over(partition by name, value order by bind_rn ) id2 ,
         lead(id,3 ) over(partition by name, value order by bind_rn ) id3 ,
         lead(id,4 ) over(partition by name, value order by bind_rn ) id4 ,
         bind_rn
    from( select tab1.name, i0.id, i0.tab1value value, bind_rn
         from tab1, tab2 i0,
              (select 0 bind_rn, :l_id0 arg_value from dual union
              select 1 , :l_id1 from dual union
              select 2 , :l_id2 from dual union
              select 3 , :l_id3 from dual union
              select 4 , :l_id4 from dual ) table_of_args
         where tab1.name='name1' and i0.tab1value=tab1.value
    -- and i0.id in (0,10,20,30,40)
    and i0.id = table_of_args.arg_value
    )) where bind_rn = 0;
    -- Full Test Case
    -- table setup
    drop table tab1;
    drop table tab2;
    create table tab1(name varchar2(100), value number) pctfree 0;
    create table tab2(id number, tab1value number) pctfree 0;
    begin
    for x in 0 .. 1600 loop
    for y in 1 .. 1600 loop
         insert into tab1 values ('name' || x, y);
    end loop;
    end loop;
    end;
    -- 15000 results in 225,000,000
    -- 1600 results in 2,560,000
    begin
    for x in 0 .. 1600 loop
    for y in 1 .. 1600 loop
         insert into tab2 values (x, y);
    end loop;
    end loop;
    end;
    commit;
    CREATE BITMAP INDEX NAME_BITMAP ON TAB1(NAME);
    EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'JTOMMANEY',TABNAME => 'TAB1', -
         estimate_percent => 20,     CASCADE => TRUE);
    EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'JTOMMANEY',TABNAME => 'TAB2', -
         estimate_percent => 20,     CASCADE => TRUE);
    alter session set optimizer_mode = 'RULE';
    -- set up some views both the original approach, and the analytis approach
    create view original_5_tab2_tables_join as
    select tab1.name name,
         i0.id id0, i0.tab1value value0,
         i1.id id1, i1.tab1value value1,
         i2.id id2, i2.tab1value value2,
         i3.id id3, i3.tab1value value3,
         i4.id id4, i4.tab1value value4
    from tab1,
    tab2 i0, tab2 i1, tab2 i2, tab2 i3, tab2 i4
    where tab1.name='name1'
    and (i0.id=0 and i0.tab1value=tab1.value)
    and (i1.id=10 and i1.tab1value=tab1.value)
    and (i2.id=20 and i2.tab1value=tab1.value)
    and (i3.id=30 and i3.tab1value=tab1.value)
    and (i4.id=40 and i4.tab1value=tab1.value);
    create view replace_5_tab2_joins as
    select name,
         id0, value value0,
         id1, value value1,
         id2, value value2,
         id3, value value3,
         id4, value value4
    from ( select name, id, value,
         lead(id,0 ) over(partition by name, value order by rn ) id0 ,
         lead(id,1 ) over(partition by name, value order by rn ) id1 ,
         lead(id,2 ) over(partition by name, value order by rn ) id2 ,
         lead(id,3 ) over(partition by name, value order by rn ) id3 ,
         lead(id,4 ) over(partition by name, value order by rn ) id4 ,
    rn from( select tab1.name, i0.id, i0.tab1value value,
    (row_number() over (partition by tab1value order by i0.id )) -1 rn
    from tab1, tab2 i0 where tab1.name='name1' and i0.tab1value=tab1.value
    and i0.id in (0,10,20,30,40)
    )) where rn = 0;
    create view original_10_tab2_tables_join as
    select tab1.name name,
         i0.id id0, i0.tab1value value0,
         i1.id id1, i1.tab1value value1,
         i2.id id2, i2.tab1value value2,
         i3.id id3, i3.tab1value value3,
         i4.id id4, i4.tab1value value4,
         i5.id id5, i5.tab1value value5,
         i6.id id6, i6.tab1value value6,
         i7.id id7, i7.tab1value value7,
         i8.id id8, i8.tab1value value8,
         i9.id id9, i9.tab1value value9
    from tab1,
    tab2 i0, tab2 i1, tab2 i2, tab2 i3, tab2 i4,
    tab2 i5, tab2 i6, tab2 i7, tab2 i8, tab2 i9
    where tab1.name='name1'
    and (i0.id=0 and i0.tab1value=tab1.value)
    and (i1.id=10 and i1.tab1value=tab1.value)
    and (i2.id=20 and i2.tab1value=tab1.value)
    and (i3.id=30 and i3.tab1value=tab1.value)
    and (i4.id=40 and i4.tab1value=tab1.value)
    and (i5.id=50 and i5.tab1value=tab1.value)
    and (i6.id=60 and i6.tab1value=tab1.value)
    and (i7.id=70 and i7.tab1value=tab1.value)
    and (i8.id=80 and i8.tab1value=tab1.value)
    and (i9.id=90 and i9.tab1value=tab1.value);
    create view replace_10_tab2_joins as
    select name,
         id0, value value0,
         id1, value value1,
         id2, value value2,
         id3, value value3,
         id4, value value4,
         id5, value value5,
         id6, value value6,
         id7, value value7,
         id8, value value8,
         id9, value value9
    from ( select name, id, value,
         lead(id,0 ) over(partition by name, value order by rn ) id0 ,
         lead(id,1 ) over(partition by name, value order by rn ) id1 ,
         lead(id,2 ) over(partition by name, value order by rn ) id2 ,
         lead(id,3 ) over(partition by name, value order by rn ) id3 ,
         lead(id,4 ) over(partition by name, value order by rn ) id4 ,
         lead(id,5 ) over(partition by name, value order by rn ) id5 ,
         lead(id,6 ) over(partition by name, value order by rn ) id6 ,
         lead(id,7 ) over(partition by name, value order by rn ) id7 ,
         lead(id,8 ) over(partition by name, value order by rn ) id8 ,
         lead(id,9 ) over(partition by name, value order by rn ) id9 ,
    rn from( select tab1.name, i0.id, i0.tab1value value,
    (row_number() over (partition by tab1value order by i0.id )) -1 rn
    from tab1, tab2 i0 where tab1.name='name1' and i0.tab1value=tab1.value
    and i0.id in (0,10,20,30,40,50,60,70,80,90)
    )) where rn = 0;
    -- set up some views both the original approach, and the analytics approach
    spool cr_v1.sql  may need to clean up heading, linefeed from created file
    begin
    dbms_output.put_line('create or replace view original_160_joins as select /*+ rule */ tab1.name ');
    for x in 0 .. 160 loop
    dbms_output.put_line( ',i' || x || '.id id' || x || ' ,i' || x || '.tab1value value' || x ) ;
    end loop;
    dbms_output.put_line('from tab1' );
    for x in 0 .. 160 loop
    dbms_output.put_line( ',tab2 i' || x ) ;
    end loop;
    dbms_output.put_line(' where tab1.name = ''name1''' );
    for x in 0 .. 160 loop
    dbms_output.put_line( ' and i' || x || '.id=' || (x * 10) || ' and i' || x || '.tab1value=tab1.value ' ) ;
    end loop;
    dbms_output.put_line( ' ;');
    end;
    --spool off
    --@cr_v1.sql
    spool cr_v2.sql may need to clean up heading, linefeed from created file
    begin
    dbms_output.put_line('create or replace view analytics_2_joins as select name ');
    for x in 0 .. 160 loop
    dbms_output.put_line( ',id' || x || ', value value' || x ) ;
    end loop;
    dbms_output.put_line('from ( select name, id, value ' );
    for x in 0 .. 160 loop
    dbms_output.put_line( ',lead(id,' || x || ') over(partition by name, value order by rn ) id' || x ) ;
    end loop;
    dbms_output.put_line(' , rn from( select tab1.name, i0.id, i0.tab1value value, ');
    dbms_output.put_line(' (row_number() over (partition by tab1value order by i0.id )) -1 rn ');
    dbms_output.put_line(' from tab1, tab2 i0 where tab1.name=''name1'' and i0.tab1value=tab1.value and i0.id in ( ');
    for x in 0 .. 159 loop
    dbms_output.put_line( (x * 10) || ',' ) ;
    end loop;
    dbms_output.put_line( ' 1600))) where rn = 0;');
    end;
    --spool off
    --@cr_v2.sql
    -- We now have 6 views established
    -- Original Approach     Analytics Approach w/ 1 tab2 reference
    -- 5 tab2s     original_5_tab2_tables_join      replace_5_tab2_joins
    -- 10 tab2s     original_10_tab2_tables_join      replace_10_tab2_joins
    --160 tab2s original_160_joins          analytics_2_joins
    -- plus we will use call the version with bind variables, but not from a view.
    -- Data validation:
    select 'orig_minus_new: ' || count(*) from
    ( select * from original_5_tab2_tables_join minus select * from replace_5_tab2_joins ) union
    select 'new_minus_orig: ' || count(*) from
    ( select * from replace_5_tab2_joins minus select * from original_5_tab2_tables_join );
    select 'orig_minus_new: ' || count(*) from
    ( select * from original_10_tab2_tables_join minus select * from replace_10_tab2_joins ) union
    select 'new_minus_orig: ' || count(*) from
    ( select * from replace_10_tab2_joins minus select * from original_10_tab2_tables_join );
    select 'orig_minus_new: ' || count(*) from
    ( select * from original_160_joins minus select * from analytics_2_joins );
    select 'new_minus_orig: ' || count(*) from
    ( select * from analytics_2_joins minus select * from original_160_joins );
    -- Performance test
    alter session set workarea_size_policy=manual ;
    alter session set sort_area_size = 64000000;
    alter session set hash_area_size = 64000000;
    set autotrace traceonly stat
    select * from original_5_tab2_tables_join;
    select * from replace_5_tab2_joins;
    select * from original_10_tab2_tables_join;      
    select * from replace_10_tab2_joins;
    select * from analytics_2_joins;
    --select * from original_160_joins;          
    -- execute a verions of the smaller analytics approch with bind variables
    -- referencing the binds within the numbered in-line view is needed only if
    -- the id0, id1, id2 values do not follow the ascending pattern shown in the
    -- example. This will handle case where id0 = 30, id2 =20, id4 = 40 , etc.
    variable l_id0 number;
    variable l_id1 number;
    variable l_id2 number;
    variable l_id3 number;
    variable l_id4 number;
    exec :l_id1 := 0;
    exec :l_id3 := 10;
    exec :l_id2 := 20;
    exec :l_id0 := 30;
    exec :l_id4 := 40;
    select name, bind_rn,
         id0, value value0,
         id1, value value1,
         id2, value value2,
         id3, value value3,
         id4, value value4
    from ( select name, id, value,
         lead(id,0 ) over(partition by name, value order by bind_rn ) id0 ,
         lead(id,1 ) over(partition by name, value order by bind_rn ) id1 ,
         lead(id,2 ) over(partition by name, value order by bind_rn ) id2 ,
         lead(id,3 ) over(partition by name, value order by bind_rn ) id3 ,
         lead(id,4 ) over(partition by name, value order by bind_rn ) id4 ,
         bind_rn
    from( select tab1.name, i0.id, i0.tab1value value, bind_rn
         from tab1, tab2 i0,
              (select 0 bind_rn, :l_id0 arg_value from dual union
              select 1 , :l_id1 from dual union
              select 2 , :l_id2 from dual union
              select 3 , :l_id3 from dual union
              select 4 , :l_id4 from dual ) table_of_args
         where tab1.name='name1' and i0.tab1value=tab1.value
    -- and i0.id in (0,10,20,30,40)
    and i0.id = table_of_args.arg_value
    )) where bind_rn = 0;
    JT(147)@JTDB10G>select * from original_5_tab2_tables_join;
    1600 rows selected.
    Statistics
    8 recursive calls
    2 db block gets
    20553 consistent gets
    18555 physical reads
    0 redo size
    52052 bytes sent via SQL*Net to client
    1250 bytes received via SQL*Net from client
    81 SQL*Net roundtrips to/from client
    0 sorts (memory)
    0 sorts (disk)
    1600 rows processed
    JT(147)@JTDB10G>select * from replace_5_tab2_joins;
    1600 rows selected.
    Statistics
    8 recursive calls
    2 db block gets
    4101 consistent gets
    3710 physical reads
    0 redo size
    52052 bytes sent via SQL*Net to client
    1250 bytes received via SQL*Net from client
    81 SQL*Net roundtrips to/from client
    2 sorts (memory)
    0 sorts (disk)
    1600 rows processed
    JT(147)@JTDB10G>select * from original_10_tab2_tables_join;
    1600 rows selected.
    Statistics
    0 recursive calls
    0 db block gets
    41016 consistent gets
    37115 physical reads
    0 redo size
    85636 bytes sent via SQL*Net to client
    1250 bytes received via SQL*Net from client
    81 SQL*Net roundtrips to/from client
    0 sorts (memory)
    0 sorts (disk)
    1600 rows processed
    JT(147)@JTDB10G>select * from replace_10_tab2_joins;
    1600 rows selected.
    Statistics
    0 recursive calls
    0 db block gets
    4099 consistent gets
    3710 physical reads
    0 redo size
    85636 bytes sent via SQL*Net to client
    1250 bytes received via SQL*Net from client
    81 SQL*Net roundtrips to/from client
    2 sorts (memory)
    0 sorts (disk)
    1600 rows processed
    JT(147)@JTDB10G>select * from analytics_2_joins;
    1600 rows selected.
    Statistics
    0 recursive calls
    0 db block gets
    4099 consistent gets
    3710 physical reads
    0 redo size
    1112904 bytes sent via SQL*Net to client
    1250 bytes received via SQL*Net from client
    81 SQL*Net roundtrips to/from client
    2 sorts (memory)
    0 sorts (disk)
    1600 rows processed
    JT(147)@JTDB10G>--select * from original_160_joins;
    JT(147)@JTDB10G>
    JT(147)@JTDB10G>----------------------------------------------------------------------------------------
    JT(147)@JTDB10G>-- execute a verions of the smaller analytics approch with bind variables
    JT(147)@JTDB10G>-- referencing the binds within the numbered in-line view is needed only if
    JT(147)@JTDB10G>-- the id0, id1, id2 values do not follow the ascending pattern shown in the
    JT(147)@JTDB10G>-- example. This will handle case where id0 = 30, id2 =20, id4 = 40 , etc.
    JT(147)@JTDB10G>----------------------------------------------------------------------------------------
    JT(147)@JTDB10G>
    JT(147)@JTDB10G>variable l_id0 number;
    JT(147)@JTDB10G>variable l_id1 number;
    JT(147)@JTDB10G>variable l_id2 number;
    JT(147)@JTDB10G>variable l_id3 number;
    JT(147)@JTDB10G>variable l_id4 number;
    JT(147)@JTDB10G>
    JT(147)@JTDB10G>exec :l_id1 := 0;
    PL/SQL procedure successfully completed.
    JT(147)@JTDB10G>exec :l_id3 := 10;
    PL/SQL procedure successfully completed.
    JT(147)@JTDB10G>exec :l_id2 := 20;
    PL/SQL procedure successfully completed.
    JT(147)@JTDB10G>exec :l_id0 := 30;
    PL/SQL procedure successfully completed.
    JT(147)@JTDB10G>exec :l_id4 := 40;
    PL/SQL procedure successfully completed.
    JT(147)@JTDB10G>
    JT(147)@JTDB10G>select name, bind_rn,
    2      id0, value value0,
    3      id1, value value1,
    4      id2, value value2,
    5      id3, value value3,
    6      id4, value value4
    7 from ( select name, id, value,
    8      lead(id,0 ) over(partition by name, value order by bind_rn ) id0 ,
    9      lead(id,1 ) over(partition by name, value order by bind_rn ) id1 ,
    10      lead(id,2 ) over(partition by name, value order by bind_rn ) id2 ,
    11      lead(id,3 ) over(partition by name, value order by bind_rn ) id3 ,
    12      lead(id,4 ) over(partition by name, value order by bind_rn ) id4 ,
    13      bind_rn
    14 from( select tab1.name, i0.id, i0.tab1value value, bind_rn
    15      from tab1, tab2 i0,
    16           (select 0 bind_rn, :l_id0 arg_value from dual union
    17           select 1 , :l_id1 from dual union
    18           select 2 , :l_id2 from dual union
    19           select 3 , :l_id3 from dual union
    20           select 4 , :l_id4 from dual ) table_of_args
    21      where tab1.name='name1' and i0.tab1value=tab1.value
    22 -- and i0.id in (0,10,20,30,40)
    23 and i0.id = table_of_args.arg_value
    24 )) where bind_rn = 0;
    1600 rows selected.
    Statistics
    1 recursive calls
    0 db block gets
    4099 consistent gets
    3707 physical reads
    0 redo size
    52111 bytes sent via SQL*Net to client
    1250 bytes received via SQL*Net from client
    81 SQL*Net roundtrips to/from client
    2 sorts (memory)
    0 sorts (disk)
    1600 rows processed

  • Hash join

    I have an index on CAT_MAP_ID column of STM_RPT_ITEM_PH6_MV but I don't know why it's not using nested look join for 21 rows returned (outer) to join 641k rows in STM_RPT_ITEM_PH6_MV table. I think that's the reason this query is consuming very high TEMP (87GB), can anyone help me explain this:
    | Id  | Operation                             | Name                        | E-Rows |  OMem |  1Mem | Used-Mem | Used-Tmp|
    |   0 | INSERT STATEMENT                      |                             |        |       |       |          |         |
    |   1 |  SORT GROUP BY                        |                             |      1 |   131M|  3585K|   90M (1)|     118K|
    |*  2 |   VIEW                                |                             |      1 |       |       |          |         |
    |   3 |    SORT UNIQUE                        |                             |      1 |   261M|  4982K|   90M (1)|         |
    |*  4 |     WINDOW SORT PUSHED RANK           |                             |      1 |   511M|  6878K|  172M (1)|         |
    |   5 |      NESTED LOOPS OUTER               |                             |      1 |       |       |          |         |
    |   6 |       NESTED LOOPS                    |                             |      1 |       |       |          |         |
    *|*  7 |        HASH JOIN                      |                             |      1 |  2047M|    75M|  470M (1)|      87M|*
    |   8 |         MAT_VIEW ACCESS BY INDEX ROWID| BSC_RPT_REBSUM_STRUCT_LI_MV |     21 |       |       |          |         |
    |   9 |          NESTED LOOPS                 |                             |   3960 |       |       |          |         |
    |  10 |           NESTED LOOPS                |                             |    185 |       |       |          |         |
    |* 11 |            HASH JOIN                  |                             |   2638 |  1465K|   902K| 4966K (0)|         |
    |* 12 |             HASH JOIN                 |                             |   4193 |   841K|   841K| 4992K (0)|         |
    |  13 |              TABLE ACCESS FULL        | BSC_RPT_REBSUM_TEMP         |   4193 |       |       |          |         |
    |  14 |              TABLE ACCESS FULL        | BSC_RPT_REBSUM_S1           |  83548 |       |       |          |         |
    |  15 |             MAT_VIEW ACCESS FULL      | BSC_RPT_REBSUM_MEM_MV       |  52555 |       |       |          |         |
    |* 16 |            TABLE ACCESS BY INDEX ROWID| MN_BUCKET_LINE              |      1 |       |       |          |         |
    |* 17 |             INDEX RANGE SCAN          | REBATEPAYMENTGRP            |   1460 |       |       |          |         |
    |* 18 |           INDEX RANGE SCAN            | BSC_RPT_STRUCT_LI_MV_IDX1   |     22 |       |       |          |         |
    |  19 |         MAT_VIEW ACCESS FULL          | BSC_RPT_ITEM_PH6_MV         *|    641K|*       |       |          |         |
    |* 20 |        INDEX UNIQUE SCAN              | MN_10291_PK                 |      1 |       |       |          |         |
    |  21 |       TABLE ACCESS BY INDEX ROWID     | BSC_SPLIT_PMT               |      1 |       |       |          |         |
    |* 22 |        INDEX RANGE SCAN               | BSC_904200_IDX1             |      1 |       |       |          |         |
    Predicate Information (identified by operation id):
       2 - filter("RPT"."RNK"=1)
       4 - filter(ROW_NUMBER() OVER ( PARTITION BY "BUCK_LI"."BUCKET_LINE_ID" ORDER BY
                  INTERNAL_FUNCTION("ITEM_VW"."BSC_PHLEVEL") DESC )<=1)
       7 - access("LIMV"."CAT_MAP_ID"="ITEM_VW"."CAT_MAP_ID" AND "ITEM_VW"."ITEM_ID"="BUCK_LI"."SALE_ITEM_ID")
      11 - access("MEM_MV"."PRC_PROGRAM_ID"="S1"."PRC_PROGRAM_ID" AND
                  "MEM_MV"."PARENT_MEMBER_ID"="S1"."MEMBER_ID_CUST")
      12 - access("TEMP"."CONTRACT_ID"="S1"."CONTRACT_ID" AND "TEMP"."REBATE_PMT_ID"="S1"."REBATE_PMT_ID")
      16 - filter(("BUCK_LI"."PMT_BENEFIT_ID" IS NOT NULL AND "BUCK_LI"."INCLUSION_TYPE"='INC' AND
                  "MEM_MV"."CHILD_MEMBER_ID"="BUCK_LI"."SALE_CONTRACTED_CUST_ID"))
      17 - access("TEMP"."REBATE_PMT_ID"="BUCK_LI"."REBATE_PMT_ID")
      18 - access("LIMV"."PRC_PROGRAM_ID"="S1"."PRC_PROGRAM_ID")
      20 - access("PRC"."PRC_PROGRAM_ID"="S1"."PRC_PROGRAM_ID")
      22 - access("TEMP"."REBATE_PMT_ID"="SPLIT"."REBATE_PMT_ID")
           filter("SPLIT"."REBATE_PMT_ID" IS NOT NULL)Note
    - dynamic sampling used for this statement
    - Warning: basic plan statistics not available. These are only collected when:
    * hint 'gather_plan_statistics' is used for the statement or
    * parameter 'statistics_level' is set to 'ALL', at session or system level
    Query Is:
    INSERT INTO MDK_TAB1
                (sale_id, struct_doc_id, pdflg, member_id_cust, paid_end_date, payee, map_name, STM_phlevel, STM_phcode, STM_old_material_num, sold_to_cust_id, member_grp_name,
                   prc_program_id, STM_r_af_type, rebate_pmt_id_num, rebate_pmt_id, sale_inv_qty, sales, earn_rebate_amt)
       SELECT   rpt.sale_id, rpt.struct_doc_id, rpt.pdflg, rpt.member_id_cust, rpt.paid_end_date, rpt.payee, rpt.map_name, rpt.STM_phlevel,
                rpt.STM_phcode, rpt.STM_old_material_num, rpt.sold_to_cust_id, rpt.member_grp_name, rpt.prc_program_id, rpt.STM_r_af_type, rpt.rebate_pmt_id_num,
                   rpt.rebate_pmt_id, rpt.sales_units, rpt.sales, SUM (rpt.earn_rebate_amt) earn_rebate_amt
           FROM (SELECT DISTINCT buck_li.sale_id, temp.contract_id struct_doc_id,
                                 temp.pdflg, s1.member_id_cust,
                                 temp.paid_end_date, SPLIT.payee,
                                 item_vw.map_name, item_vw.STM_phlevel,
                                 item_vw.STM_phcode, item_vw.STM_old_material_num,
                                 buck_li.sale_contracted_cust_id sold_to_cust_id,
                                 mem_mv.child_name member_grp_name, s1.prc_program_id, s1.STM_r_af_type,
                                 s1.rebate_pmt_id_num, s1.rebate_pmt_id,
                                 buck_li.sale_inv_qty AS sales_units,
                                 NULLIF (buck_li.sale_ext_amt, 0) sales,
                                 NULLIF
                                     (buck_li.STM_payment_amount, 0) earn_rebate_amt,
                                 ROW_NUMBER () OVER (PARTITION BY buck_li.bucket_line_id ORDER BY item_vw.STM_phlevel DESC)
                       rnk
                            FROM STM_rpt_rebsum_s1 s1,
                                 mn_bucket_line buck_li,
                                 STM_rpt_item_ph6_mv item_vw,
                                 STM_rpt_rebsum_struct_li_mv limv,
                                 STM_rpt_rebsum_mem_mv mem_mv,
                                 STM_rpt_rebsum_temp temp,
                                 STM_split_pmt SPLIT,
                                 mn_prc_program prc
                           WHERE temp.contract_id = s1.contract_id
                             AND temp.rebate_pmt_id = s1.rebate_pmt_id
                             AND temp.rebate_pmt_id = SPLIT.rebate_pmt_id(+)
                             AND temp.rebate_pmt_id = buck_li.rebate_pmt_id
                             AND limv.prc_program_id = s1.prc_program_id
                             AND prc.prc_program_id = s1.prc_program_id
                             AND mem_mv.prc_program_id = s1.prc_program_id
                             AND mem_mv.parent_member_id = s1.member_id_cust
                             AND *limv.cat_map_id = item_vw.cat_map_id*                        
                             AND item_vw.item_id = buck_li.sale_item_id
                             AND mem_mv.child_member_id = buck_li.sale_contracted_cust_id
                             AND buck_li.pmt_benefit_id IS NOT NULL
                             AND buck_li.inclusion_type = 'INC') rpt
          WHERE rpt.rnk = 1
       GROUP BY rpt.sale_id,
                rpt.struct_doc_id,
                rpt.pdflg,
                rpt.member_id_cust,
                rpt.paid_end_date,
                rpt.payee,
                rpt.map_name,
                rpt.STM_phlevel,
                rpt.STM_phcode,
                rpt.STM_old_material_num,
                rpt.sold_to_cust_id,
                rpt.member_grp_name,
                rpt.prc_program_id,
                rpt.STM_r_af_type,
                rpt.rebate_pmt_id_num,
                rpt.rebate_pmt_id,
                rpt.sales_units,
                rpt.sales;Edited by: 988590 on Feb 21, 2013 10:33 AM

    Sorry for messing with the code thingy, it's the first timer's mistake, here is the formatted version:
    | Id  | Operation                             | Name                        | E-Rows |  OMem |  1Mem | Used-Mem | Used-Tmp|
    |   0 | INSERT STATEMENT                      |                             |        |       |       |          |         |
    |   1 |  SORT GROUP BY                        |                             |      1 |   133M|  3616K|   90M (1)|     120K|
    |*  2 |   VIEW                                |                             |      1 |       |       |          |         |
    |   3 |    SORT UNIQUE                        |                             |      1 |   266M|  5026K|   90M (1)|         |
    |*  4 |     WINDOW SORT PUSHED RANK           |                             |      1 |   520M|  6933K|  172M (1)|         |
    |   5 |      NESTED LOOPS OUTER               |                             |      1 |       |       |          |         |
    |   6 |       NESTED LOOPS                    |                             |      1 |       |       |          |         |
    |*  7 |        HASH JOIN                      |                             |      1 |  2047M|   120M|  419M (1)|      93M|
    |   8 |         MAT_VIEW ACCESS BY INDEX ROWID| BSC_RPT_REBSUM_STRUCT_LI_MV |     21 |       |       |          |         |
    |   9 |          NESTED LOOPS                 |                             |   5468 |       |       |          |         |
    |  10 |           NESTED LOOPS                |                             |    255 |       |       |          |         |
    |* 11 |            HASH JOIN                  |                             |   2645 |  1465K|   902K| 3386K (0)|         |
    |* 12 |             HASH JOIN                 |                             |   4202 |   841K|   841K| 5115K (0)|         |
    |  13 |              TABLE ACCESS FULL        | BSC_RPT_REBSUM_TEMP         |   4202 |       |       |          |         |
    |  14 |              TABLE ACCESS FULL        | BSC_RPT_REBSUM_S1           |  83564 |       |       |          |         |
    |  15 |             MAT_VIEW ACCESS FULL      | BSC_RPT_REBSUM_MEM_MV       |  52596 |       |       |          |         |
    |* 16 |            TABLE ACCESS BY INDEX ROWID| MN_BUCKET_LINE              |      1 |       |       |          |         |
    |* 17 |             INDEX RANGE SCAN          | REBATEPAYMENTGRP            |   1465 |       |       |          |         |
    |* 18 |           INDEX RANGE SCAN            | BSC_RPT_STRUCT_LI_MV_IDX1   |     22 |       |       |          |         |
    |  19 |         MAT_VIEW ACCESS FULL          | BSC_RPT_ITEM_PH6_MV         |    641K|       |       |          |         |
    |* 20 |        INDEX UNIQUE SCAN              | MN_10291_PK                 |      1 |       |       |          |         |
    |  21 |       TABLE ACCESS BY INDEX ROWID     | BSC_SPLIT_PMT               |      1 |       |       |          |         |
    |* 22 |        INDEX RANGE SCAN               | BSC_904200_IDX1             |      1 |       |       |          |         |
    Predicate Information (identified by operation id):
       2 - filter("RPT"."RNK"=1)
       4 - filter(ROW_NUMBER() OVER ( PARTITION BY "BUCK_LI"."BUCKET_LINE_ID" ORDER BY
                  INTERNAL_FUNCTION("ITEM_VW"."BSC_PHLEVEL") DESC )<=1)
       7 - access("LIMV"."CAT_MAP_ID"="ITEM_VW"."CAT_MAP_ID" AND "ITEM_VW"."ITEM_ID"="BUCK_LI"."SALE_ITEM_ID")
      11 - access("MEM_MV"."PRC_PROGRAM_ID"="S1"."PRC_PROGRAM_ID" AND
                  "MEM_MV"."PARENT_MEMBER_ID"="S1"."MEMBER_ID_CUST")
      12 - access("TEMP"."CONTRACT_ID"="S1"."CONTRACT_ID" AND "TEMP"."REBATE_PMT_ID"="S1"."REBATE_PMT_ID")
      16 - filter(("BUCK_LI"."PMT_BENEFIT_ID" IS NOT NULL AND "BUCK_LI"."INCLUSION_TYPE"='INC' AND
                  "MEM_MV"."CHILD_MEMBER_ID"="BUCK_LI"."SALE_CONTRACTED_CUST_ID"))
      17 - access("TEMP"."REBATE_PMT_ID"="BUCK_LI"."REBATE_PMT_ID")
      18 - access("LIMV"."PRC_PROGRAM_ID"="S1"."PRC_PROGRAM_ID")
      20 - access("PRC"."PRC_PROGRAM_ID"="S1"."PRC_PROGRAM_ID")
      22 - access("TEMP"."REBATE_PMT_ID"="SPLIT"."REBATE_PMT_ID")
           filter("SPLIT"."REBATE_PMT_ID" IS NOT NULL)
    Note
       - dynamic sampling used for this statement
       - Warning: basic plan statistics not available. These are only collected when:
           * hint 'gather_plan_statistics' is used for the statement or
           * parameter 'statistics_level' is set to 'ALL', at session or system level
    INSERT INTO BSC_RPT_REBSUM_S3_TEMP
                (sale_id, struct_doc_id, pdflg, member_id_cust, paid_end_date, payee, map_name, bsc_phlevel, bsc_phcode, bsc_old_material_num, sold_to_cust_id, member_grp_name,
                   prc_program_id, bsc_r_af_type, rebate_pmt_id_num, rebate_pmt_id, sale_inv_qty, sales, earn_rebate_amt)
       SELECT   rpt.sale_id, rpt.struct_doc_id, rpt.pdflg, rpt.member_id_cust, rpt.paid_end_date, rpt.payee, rpt.map_name, rpt.bsc_phlevel,
                rpt.bsc_phcode, rpt.bsc_old_material_num, rpt.sold_to_cust_id, rpt.member_grp_name, rpt.prc_program_id, rpt.bsc_r_af_type, rpt.rebate_pmt_id_num,
                   rpt.rebate_pmt_id, rpt.sales_units, rpt.sales, SUM (rpt.earn_rebate_amt) earn_rebate_amt
           FROM (SELECT DISTINCT buck_li.sale_id, temp.contract_id struct_doc_id,
                                 temp.pdflg, s1.member_id_cust,
                                 temp.paid_end_date, SPLIT.payee,
                                 item_vw.map_name, item_vw.bsc_phlevel,
                                 item_vw.bsc_phcode, item_vw.bsc_old_material_num,
                                 buck_li.sale_contracted_cust_id sold_to_cust_id,
                                 mem_mv.child_name member_grp_name, s1.prc_program_id, s1.bsc_r_af_type,
                                 s1.rebate_pmt_id_num, s1.rebate_pmt_id,
                                 buck_li.sale_inv_qty AS sales_units,
                                 NULLIF (buck_li.sale_ext_amt, 0) sales,
                                 NULLIF
                                     (buck_li.bsc_payment_amount, 0) earn_rebate_amt,
                                 ROW_NUMBER () OVER (PARTITION BY buck_li.bucket_line_id ORDER BY item_vw.bsc_phlevel DESC)
                       rnk
                            FROM bsc_rpt_rebsum_s1 s1,
                                 mn_bucket_line buck_li,
                                 bsc_rpt_item_ph6_mv item_vw,
                                 bsc_rpt_rebsum_struct_li_mv limv,
                                 bsc_rpt_rebsum_mem_mv mem_mv,
                                 bsc_rpt_rebsum_temp temp,
                                 bsc_split_pmt SPLIT,
                                 mn_prc_program prc
                           WHERE temp.contract_id = s1.contract_id
                             AND temp.rebate_pmt_id = s1.rebate_pmt_id
                             AND temp.rebate_pmt_id = SPLIT.rebate_pmt_id(+)
                             AND temp.rebate_pmt_id = buck_li.rebate_pmt_id
                             AND limv.prc_program_id = s1.prc_program_id
                             AND prc.prc_program_id = s1.prc_program_id
                             AND mem_mv.prc_program_id = s1.prc_program_id
                             AND mem_mv.parent_member_id = s1.member_id_cust
                             AND limv.cat_map_id = item_vw.cat_map_id
                             AND item_vw.item_id = buck_li.sale_item_id
                             AND mem_mv.child_member_id = buck_li.sale_contracted_cust_id
                             AND buck_li.pmt_benefit_id IS NOT NULL
                             AND buck_li.inclusion_type = 'INC') rpt
          WHERE rpt.rnk = 1
       GROUP BY rpt.sale_id,
                rpt.struct_doc_id,
                rpt.pdflg,
                rpt.member_id_cust,
                rpt.paid_end_date,
                rpt.payee,
                rpt.map_name,
                rpt.bsc_phlevel,
                rpt.bsc_phcode,
                rpt.bsc_old_material_num,
                rpt.sold_to_cust_id,
                rpt.member_grp_name,
                rpt.prc_program_id,
                rpt.bsc_r_af_type,
                rpt.rebate_pmt_id_num,
                rpt.rebate_pmt_id,
                rpt.sales_units,
                rpt.sales;
    COLUMN_NAME          NUM_DISTINCT  NUM_NULLS NUM_BUCKETS SAMPLE_SIZE HISTOGRAM
    BSC_OLD_MATERIAL_NUM        55394     583842           1       57907 NONE
    BSC_NUM_SHEETS                 28          0           1      641691 NONE
    BSC_PHCODE                  69997     207552           1      434160 NONE
    BSC_PHLEVEL                     6     207552           1      434160 NONE
    BSC_PROFIT_CENTER              10          0           1      641691 NONE
    BSC_COST                    14966      42821           1      598874 NONE
    MAP_NAME                    61277          0           1      641691 NONE
    CAT_MAP_ID                  72241          0           1      641691 NONE
    ITEM_ID                     64299          0           1      641691 NONE               Still don't get it why 21 rows hasing with 641k - it looks a bad idea, maybe I should build histograms here?
    Any idea.

  • Optimizer choosing hash joins even when slower

    We have several queries where joins are being evaluated by full scans / hash joins even when forcing index use results in an execution time about a quarter the duration of the hash join plan. It still happens if I run DMS_STATS.GATHER_TABLE_STATS with FOR ALL COLUMNS.
    Is there a stats gathering option which is more likely to result in an indexd join without having to get developers to put optimizer hints in their queries?
    11g on SuSE 10.
    Many thanks.

    user10400178 wrote:
    That would require me to post a large amount of schema information as well to be of any added value.
    Surely there are some general recommendations one could make as to how to allow the optimizer to realise that joining through an index is going to be quicker than doing a full scan and hash join to a table.If you don't want to post the plans, then as a first step you basically need to verify yourself if the cardinality estimates returned by the execution plan correspond roughly to the actual cardinalities.
    E.g. in your execution plan there are steps like "FULL TABLE SCAN" and these operations likely have a corresponding "FILTER" predicate in the "Predicate Information" section below the plan.
    As first step you should run simple count queries ("select count(*) from ... where <FILTER/ACCESS predicates>") on the tables involved using the "FILTER" and "ACCESS" predicates mentioned to compare if the returned number of rows is in the same ballpark than the estimates mentioned in the plan.
    If these estimates are already way off then you know that for some reason the optimizer makes wrong assumptions and that's probably the reason why the suboptimal access pattern is preferred.
    One potential reason could be correlated column values, but since you're already on 11g you could make use of extended column statistics. See here for more details:
    http://download.oracle.com/docs/cd/B28359_01/server.111/b28274/stats.htm#BEIEEIJA
    Another reason might simply that you're choosing a too low "estimate" sample size for the statistics collection. In 11g you should always use the DBMS_STATS.AUTO_SAMPLE_SIZE for the "estimate_percent" parameter of the DBMS_STATS.GATHER__STATS procedures. It should generate accurate statistics without the need to analyze all of the data. See here in Greg Rahn's blog for an example:
    http://structureddata.org/2007/09/17/oracle-11g-enhancements-to-dbms_stats/
    Regarding the histograms: Oracle 11g by default generates histograms if it deems them to be beneficial. It is controlled by the parameter "METHOD_OPT" which has the default value of "FOR ALL COLUMNS SIZE AUTO". The "SIZE" keyword determines the generation of histograms. You could use "SIZE 1" to prevent histogram generation, "SIZE <n>" to control the number of buckets to use for the histogram or "SIZE AUTO" to let Oracle decide itself when and how to generate histograms.
    Regarding the stored outlines: You could have so called "stored outlines" that force the optimizer to stick to a certain plan. That features was introduced a long time ago and is sometimes also referred to as "plan stability", its main purpose was an attempt to smooth the transition from the rule based optimizer (RBO) to the cost based optimizer (CBO) introduced in Oracle 7 (although you can use it for other purposes, too, of course). Oracle 11g offers now the new "SQL plan management" feature that is supposed to supersede the "plan stability" feature. For more information, look here:
    http://download.oracle.com/docs/cd/B28359_01/server.111/b28274/outlines.htm#PFGRF707
    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/
    Edited by: Randolf Geist on Oct 16, 2008 4:20 PM
    Sample size note added
    Edited by: Randolf Geist on Oct 16, 2008 6:54 PM
    Outline info added

  • Generally when does optimizer use nested loop and Hash joins  ?

    Version: 11.2.0.3, 10.2
    Lets say I have a table called ORDER and ORDER_DETAIL.
    ORDER_DETAIL is the child table of ORDERS .
    This is what I understand about Nested Loop:
    When we join ORDER AND ORDER_DETAIL tables oracle will form a 'nested loop' in which for each order_ID in ORDER table (outer loop), oracle will look for corresponding multiple ORDER_IDs in the ORDER_DETAIL table.
    Is nested loop used when the driving table (ORDER in this case) is smaller than the child table (ORDER_DETAIL) ?
    Is nested loop more likely to use Indexes in general ?
    How will these two tables be joined using Hash joins ?
    When is it ideal to use hash joins  ?

    Your description of a nested loop is correct.
    The overall rule is that Oracle will use the plan that it calculates to be, in general, fastest. That mostly means fewest I/O's, but there are various factors that adjust its calculation - e.g. it expects index blocks to be cached, multiple reads entries in an index may reference the same block, full scans get multiple blocks per I/O. It also has CPU cost calculations, but they generally only become significant with function / package calls or domain indexes (spatial, text, ...).
    Nested loop with an index will require one indexed read of the child table per outer table row, so its I/O cost is roughly twice the number of rows expected to match the where clause conditions on the outer table.
    A hash join reads the of the smaller table into a hash table then matches the rows from the larger table against the hash table, so its I/O cost is the cost of a full scan of each table (unless the smaller table is too big to fit in a single in-memory hash table). Hash joins generally don't use indexes - it doesn't use the index to look up each result. It can use an index as a data source, as a narrow version of the table or a way to identify the rows satisfying the other where clause conditions.
    If you are processing the whole of both tables, Oracle is likely to use a hash join, and be very fast and efficient about it.
    If your where clause restricts it to a just few rows from the parent table and a few corresponding rows from the child table, and you have an index Oracle is likely to use a nested loops solution.
    If the tables are very small, either plan is efficient - you may be surprised by its choice.
    Don't be worry about plans with full scans and hash joins - they are usually very fast and efficient. Often bad performance comes from having to do nested loop lookups for lots of rows.

  • How to load color table in a indexed mode file??

    How to load color table in a indexed mode file??
    Actually, if i opened a indexed file and want to edit color table by loading another color table from desktop (or any other location), any way to do this through java scripting??

    continuing...
    I wrote a script to read a color table from a GIF file and save to an ACT color table file. I think it might be useful for someone.
    It goes a little more deeper than the code I posted before, as it now identifies the table size. It is important because it tells how much data to read.
    Some gif files, even if they are saved with a reduced palette (less than 256), they have all the bytes for the full color palette filled inside the file (sometimes with 0x000000). But, some gif files exported in PS via "save for web" for example, have the color table reduced to optimize file size.
    The script store all colors into an array, allowing some kind of sorting, or processing at will.
    It uses the xlib/Stream.js in xtools from Xbytor
    Here is the code:
    // reads the color table from a GIF image
    // saves to an ACT color table file format
    #include "xtools/xlib/Stream.js"
    // read the 0xA byte in hex format from the gif file
    // this byte has the color table size info at it's 3 last bits
    Stream.readByteHex = function(s) {
      function hexDigit(d) {
        if (d < 10) return d.toString();
        d -= 10;
        return String.fromCharCode('A'.charCodeAt(0) + d);
      var str = '';
      s = s.toString();
         var ch = s.charCodeAt(0xA);
        str += hexDigit(ch >> 4) + hexDigit(ch & 0xF);
      return str;
    // hex to bin conversion
    Math.base = function(n, to, from) {
         return parseInt(n, from || 10).toString(to);
    //load test image
    var img = Stream.readFromFile("~/file.gif");
    hex = Stream.readByteHex(img);      // hex string of the 0xA byte
    bin = Math.base(hex,2,16);          // binary string of the 0xA byte
    tableSize = bin.slice(5,8)          // Get the 3 bit info that defines size of the ct
    switch(tableSize)
    case '000': // 6 bytes table
      tablSize = 2
      break;
    case '001': // 12 bytes table
      tablSize = 4
      break;
    case '010': // 24 bytes table
      tablSize = 8
      break;
    case '011': // 48 bytes table
      tablSize = 16
      break;
    case '100': // 96 bytes table
      tablSize = 32
      break;
    case '101': // 192 bytes table
      tablSize = 64
      break;
    case '110': // 384 bytes table
      tablSize = 128
      break;
    case '111': // 768 bytes table
      tablSize = 256
      break;
    //========================================================
    // read a color (triplet) from the color lookup table
    // of a GIF image file | return 3 Bytes Hex String
    Stream.getTbColor = function(s, color) {
      function hexDigit(d) {
        if (d < 10) return d.toString();
        d -= 10;
        return String.fromCharCode('A'.charCodeAt(0) + d);
      var tbStart = 0xD; // Start of the color table byte location
      var colStrSz = 3; // Constant -> RGB
      var str = '';
      s = s.toString();
         for (var i = tbStart+(colStrSz*color); i < tbStart+(colStrSz*color)+colStrSz; i++) {
              var ch = s.charCodeAt(i);
              str += hexDigit(ch >> 4) + hexDigit(ch & 0xF);
          return str;
    var colorHex = [];
    importColors = function (){
         for (i=0; i< tablSize; i++){ // number of colors
              colorHex[i] = Stream.getTbColor(img, i);
    importColors();
    // remove redundant colors
    // important to determine exact color number
    function unique(arrayName){
         var newArray=new Array();
         label:for(var i=0; i<arrayName.length;i++ ){ 
              for(var j=0; j<newArray.length;j++ ){
                   if(newArray[j]==arrayName[i])
                        continue label;
              newArray[newArray.length] = arrayName[i];
         return newArray;
    colorHex = unique(colorHex);
    // we have now an array with all colors from the table in hex format
    // it can be sorted if you want to have some ordering to the exported file
    // in case, add code here.
    var colorStr = colorHex.join('');
    //=================================================================
    // Output to ACT => color triplets in hex format until 256 (Adr. dec 767)
    // if palette has less than 256 colors, is necessary to add the
    // number of colors info in decimal format to the the byte 768.
    ColorNum = colorStr.length/6;
    lstclr = colorStr.slice(-6); // get last color
    if (ColorNum < 10){
    ColorNum = '0'+ ColorNum;
    cConv = function (s){
         var opt = '';
         var str = '';
         for (i=0; i < s.length ; i++){
              for (j=0; j<2 ; j++){
                   var ch = s.charAt(i+j);
                   str += ch;
                   i ++;
              opt += String.fromCharCode(parseInt(str,16));
              str = '';
         return opt
    output = cConv(colorStr);
    // add ending file info for tables with less than 256 colors
    if (ColorNum < 256){
         emptyColors = ((768-(colorStr.length/2))/3);
         lstclr = cConv(lstclr);
         for (i=0; i < emptyColors ; i++){
              output += lstclr; // fill 256 colors
    output += String.fromCharCode(ColorNum) +'\xFF\xFF'; // add ending bytes
    Stream.writeToFile("~/file.act", output);
    PeterGun

  • Simultaneous hash joins of the same large table with many small ones?

    Hello
    I've got a typical data warehousing scenario where a HUGE_FACT table is to be joined with numerous very small lookup/dimension tables for data enrichment. Joins with these small lookup tables are mutually independent, which means that the result of any of these joins is not needed to perform another join.
    So this is a typical scenario for a hash join: the lookup table is converted into a hashed map in RAM memory, fits there without drama cause it's small and a single pass over the HUGE_FACT suffices to get the results.
    Problem is, so far as I can see it in the query plan, these hash joins are not executed simultaneously but one after another, which renders Oracle to do the full scan of the HUGE_FACT (or any intermediary enriched form of it) as many times as there are joins.
    Questions:
    - is my interpretation correct that the mentioned joins are sequential, not simultaneous?
    - if this is the case, is there any possibility to force Oracle to perform these joins simultaneously (building more than one hashed map in memory and doing the single pass over the HUGE_FACT while looking up in all of these hashed maps for matches)? If so, how to do it?
    Please note that the parallel execution of a single join at a time is not the matter of the question.
    Database version is 10.2.
    Thank you very much in advance for any response.

    user13176880 wrote:
    Questions:
    - is my interpretation correct that the mentioned joins are sequential, not simultaneous?Correct. But why do you think this is an issue? Because of this:
    which renders Oracle to do the full scan of the HUGE_FACT (or any intermediary enriched form of it) as many times as there are joins.That is (should not be) true. Oracle does one pass of the big table, and then sequentually joins to each of the hashmaps (of each of the smaller tables).
    If you show us the execution plan, we can be sure of this.
    - if this is the case, is there any possibility to force Oracle to perform these joins simultaneously (building more than one hashed map in memory and doing the single pass over the HUGE_FACT while looking up in all of these hashed maps for matches)? If so, how to do it?Yes there is. But again you should not need to resort to such a solution. What you can do is use subquery factoring (WITH clause) in conjunction with the MATERIALIZE hint to first construct the cartesian join of all of the smaller (dimension) tables. And then join the big table to that.

Maybe you are looking for

  • Photoshop Problems

    Hello, there i have some problems with my photoshop i downloaded it and it says Extracting this may take a while  and now it pop up with a message saying we've encountered the following issues installer has detected that a machine restart may be pend

  • Should I be deinterlacing?

    Hello All, I've had some old 8mm movie film transferred.  It was transferred at 18fps and was shot (transferred) on SD digital video onto a miniDV tape.  When I'm editing this footage it has lots of jaggies on my iMac screen. I'm putting this footage

  • SAP and SQL DB13 Issues

    I am experiencing issues with DB13. In Calendar Scheduled backup Jobs showing red when job is running and not dark blue, job does go green when finished. Some times it will just stay red even though in SQL it reported a success. Any help would be gra

  • Differences between ALUI and Weblogic Portal 10

    if anyone has some useful information / experience on the differences between these products - for example why you might choose one over the other...thanks.

  • Is there a way to retrieve data from a water damaged ipod?

    my ipod got water on the inside, and it wont charge. when i plug it in, the image shows it as charging but its not. im guessing that there is a short circuit, do to he water. is there a way to retrieve data from my ipod?