High cost of TABLE ACCESS BY LOCAL INDEX ROWID

Hi,
We are having a query which is running very slow, while checking the execution plan we found high cost on "TABLE ACCESS BY LOCAL INDEX ROWID"
Db version : 11.2.0.1
EBS version: 12.1.2
Os version : Aix 6.1
SID        : 567
ADDRESS    : 07000004EB12A7A8
HASH_VALUE : 556917643
MODULE     : ora_rw20_run@erpprodapp (TNS V1-V3)
PROGRAM    : ora_rw20_run@erpprodapp (TNS V1-V3)
MACHINE    : erpprodapp
CHILD CNT  : 2
[  Current SQL  ]
SELECT API.INVOICE_TYPE_LOOKUP_CODE
,   DECODE(API.INVOICE_TYPE_LOOKUP_CODE, 'CREDIT', 0, Z.AMT_VAL ) CREDIT_VAL, 0 ACCT_CR
,   API.EXCHANGE_RATE EXCHANGE_RATE
,   API.EXCHANGE_RATE_TYPE EXCHANGE_RATE_TYPE, API.INVOICE_CURRENCY_CODE INVOICE_CURRENCY_CODE
,   API.EXCHANGE_DATE EXCHANGE_DATE
FROM AP_INVOICES_ALL API, AP_INVOICE_DISTRIBUTIONS_ALL APD, (SELECT NVL(SUM(APD.AMOUNT),0) AMT_VAL
,   API.INVOICE_ID
FROM AP_INVOICES_ALL API, AP_INVOICE_DISTRIBUTIONS_ALL APD
WHERE API.INVOICE_ID = APD.INVOICE_ID
AND API.INVOICE_TYPE_LOOKUP_CODE <> :B6
AND APD.MATCH_STATUS_FLAG = 'A'
AND API.VENDOR_ID = :B5
AND API.VENDOR_SITE_ID = :B4
AND APD.ACCOUNTING_DATE < :B3
AND (API.ORG_ID = :B2
OR API.ORG_ID IS NULL)
AND APD.LINE_TYPE_LOOKUP_CODE <> :B1
GROUP BY API.INVOICE_ID) Z
WHERE Z.INVOICE_ID = API.INVOICE_ID
AND API.INVOICE_ID = APD.INVOICE_ID
AND APD.ROWID = (SELECT ROWID
FROM AP_INVOICE_DISTRIBUTIONS_ALL WHERE ROWNUM=1
AND INVOICE_ID=APD.INVOICE_ID
AND MATCH_STATUS_FLAG = 'A'
AND ACCOUNTING_DATE < :B3 )
AND API.INVOICE_TYPE_LOOKUP_CODE <> :B6
AND APD.MATCH_STATUS_FLAG = 'A'
AND API.VENDOR_ID = :B5 AND API.VENDOR_SITE_ID = :B4
AND APD.ACCOUNTING_DATE < :B3
AND (API.ORG_ID = :B2
OR API.ORG_ID IS NULL)
AND ((API.INVOICE_TYPE_LOOKUP_CODE <> :B9 )
OR ( (API.INVOICE_TYPE_LOOKUP_CODE = :B9 ) AND ( NOT EXISTS (SELECT '1'
FROM AP_INVOICE_PAYMENTS_ALL APP, AP_CHECKS_ALL APC
WHERE APP.CHECK_ID = APC.CHECK_ID
AND APP.INVOICE_ID = API.INVOICE_ID
AND APC.PAYMENT_TYPE_FLAG = 'R' ) ) ) ) AND API.INVOICE_CURRENCY_CODE =NVL( :B8
,  API.INVOICE_CURRENCY_CODE)
AND API.ACCTS_PAY_CODE_COMBINATION_ID = NVL(:B7 ,API.ACCTS_PAY_CODE_COMBINATION_ID) UNION ALL
SELECT API.INVOICE_TYPE_LOOKUP_CODE, DECODE(API.INVOICE_TYPE_LOOKUP_CODE,'CREDIT'
,   DECODE(STATUS_LOOKUP_CODE,'VOIDED', APP.AMOUNT+ NVL(DISCOUNT_AMOUNT_TAKEN
,   0) , ABS(APP.AMOUNT)+ ABS(NVL(DISCOUNT_AMOUNT_TAKEN, 0)) )
,   0) CREDIT_VAL, 0 ACCT_CR, APC.EXCHANGE_RATE EXCHANGE_RATE
,   APC.EXCHANGE_RATE_TYPE EXCHANGE_RATE_TYPE
,   API.PAYMENT_CURRENCY_CODE INVOICE_CURRENCY_CODE, APC.EXCHANGE_DATE EXCHANGE_DATE
FROM AP_INVOICES_ALL API, AP_INVOICE_PAYMENTS_ALL APP, AP_CHECKS_ALL APC
WHERE APP.INVOICE_ID = API.INVOICE_ID
AND APP.CHECK_ID = APC.CHECK_ID AND APC.STATUS_LOOKUP_CODE IN (:B15 ,:B14 ,:B13 ,:B12 ,:B11
,  :B10 )
AND API.VENDOR_ID = :B5
AND API.VENDOR_SITE_ID = :B4
AND APP.ACCOUNTING_DATE < TRUNC(:B3 )
AND ( API.ORG_ID = :B2
OR API.ORG_ID IS NULL )
AND EXISTS (
SELECT '1'
FROM AP_INVOICE_DISTRIBUTIONS_ALL APD , AP_INVOICE_LINES_ALL APIL
WHERE APD.INVOICE_ID = API.INVOICE_ID
AND APIL.INVOICE_ID = APD.INVOICE_ID
AND APD.MATCH_STATUS_FLAG ='A'
AND APIL.LINE_NUMBER = APD.INVOICE_LINE_NUMBER)
AND API.INVOICE_CURRENCY_CODE =NVL( :B8 ,API.INVOICE_CURRENCY_CODE)
AND API.ACCTS_PAY_CODE_COMBINATION_ID = NVL(:B7 ,API.ACCTS_PAY_CODE_COMBINATION_ID) UNION ALL
SELECT 'LOSS' INVOICE_TYPE_LOOKUP_CODE, 0 CREDIT_VAL, DECODE(XAL.ACCOUNTING_CLASS_CODE
,  'LOSS', ACCOUNTED_DR,0) ACCT_CR
,   XAL.CURRENCY_CONVERSION_RATE EXCHANGE_RATE , XAL.CURRENCY_CONVERSION_TYPE EXCHANGE_RATE_TYPE
,   XAL.CURRENCY_CODE INVOICE_CURRENCY_CODE
,   XAL.CURRENCY_CONVERSION_DATE EXCHANGE_DATE
FROM XLA_AE_LINES XAL, XLA_AE_HEADERS XAH, XLA_TRANSACTION_ENTITIES XTE, AP_INVOICES_ALL API
WHERE XAL.APPLICATION_ID = 200
AND XAL.AE_HEADER_ID = XAH.AE_HEADER_ID
AND XAL.ACCOUNTING_CLASS_CODE IN ( :B18 ,:B17 )
AND XAH.APPLICATION_ID = 200 AND XAH.ENTITY_ID = XTE.ENTITY_ID
AND XTE.APPLICATION_ID = 200 AND XTE.ENTITY_CODE =:B16
AND XTE.SOURCE_ID_INT_1 = API.INVOICE_ID
AND API.VENDOR_ID = :B5
AND API.VENDOR_SITE_ID = :B4
AND XAH.ACCOUNTING_DATE < :B3
AND (API.ORG_ID = :B2
OR API.ORG_ID IS NULL )
AND API.INVOICE_CURRENCY_CODE =NVL( :B8 ,API.INVOICE_CURRENCY_CODE)
AND API.ACCTS_PAY_CODE_COMBINATION_ID = NVL(:B7 ,API.ACCTS_PAY_CODE_COMBINATION_ID) UNION ALL
SELECT 'LOSS' INVOICE_TYPE_LOOKUP_CODE, 0 CREDIT_VAL, DECODE(XAL.ACCOUNTING_CLASS_CODE
,  'LOSS', ACCOUNTED_DR,0) ACCT_CR
,   XAL.CURRENCY_CONVERSION_RATE EXCHANGE_RATE , XAL.CURRENCY_CONVERSION_TYPE EXCHANGE_RATE_TYPE
,   XAL.CURRENCY_CODE INVOICE_CURRENCY_CODE
,   XAL.CURRENCY_CONVERSION_DATE EXCHANGE_DATE
FROM XLA_AE_LINES XAL, XLA_AE_HEADERS XAH, XLA_TRANSACTION_ENTITIES XTE, AP_INVOICES_ALL API, AP_CHECKS_ALL AC
,   AP_INVOICE_PAYMENTS_ALL APP
WHERE XAL.APPLICATION_ID = 200
AND XAL.AE_HEADER_ID = XAH.AE_HEADER_ID
AND XAL.ACCOUNTING_CLASS_CODE IN ( :B18 ,:B17 )
AND XAH.APPLICATION_ID = 200
AND XAH.ENTITY_ID = XTE.ENTITY_ID
AND XTE.APPLICATION_ID = 200
AND XTE.ENTITY_CODE = :B19
AND XTE.SOURCE_ID_INT_1 = AC.CHECK_ID
AND XAH.EVENT_ID = APP.ACCOUNTING_EVENT_ID
AND API.INVOICE_ID = APP.INVOICE_ID AND APP.CHECK_ID = AC.CHECK_ID
AND AC.STATUS_LOOKUP_CODE IN (:B15 ,:B14 ,:B13 , :B12 ,:B11 ,:B10 )
AND API.VENDOR_ID = :B5
AND API.VENDOR_SITE_ID = :B4
AND XAH.ACCOUNTING_DATE < :B3
AND (API.ORG_ID = :B2
OR API.ORG_ID IS NULL )
AND API.INVOICE_CURRENCY_CODE =NVL( :B8 ,API.INVOICE_CURRENCY_CODE)
AND API.ACCTS_PAY_CODE_COMBINATION_ID = NVL(:B7
,  API.ACCTS_PAY_CODE_COMBINATION_ID)
Plan hash value: 1352234085
| Id  | Operation                                | Name                         | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Ps
|   0 | SELECT STATEMENT                         |                              |       |       |  1904 (100)|          |       |
|   1 |  UNION-ALL                               |                              |       |       |            |          |       |
|   2 |   FILTER                                 |                              |       |       |            |          |       |
|   3 |    NESTED LOOPS                          |                              |       |       |            |          |       |
|   4 |     NESTED LOOPS                         |                              |     1 |    87 |    20   (5)| 00:06:09 |       |
|   5 |      NESTED LOOPS                        |                              |     1 |    60 |    17   (6)| 00:05:14 |       |
|   6 |       VIEW                               |                              |     1 |    18 |    15   (7)| 00:04:37 |       |
|   7 |        HASH GROUP BY                     |                              |     1 |    54 |    15   (7)| 00:04:37 |       |
|   8 |         NESTED LOOPS                     |                              |       |       |            |          |       |
|   9 |          NESTED LOOPS                    |                              |     1 |    54 |    14   (0)| 00:04:19 |       |
|  10 |           TABLE ACCESS BY INDEX ROWID    | AP_INVOICES_ALL              |     1 |    27 |    11   (0)| 00:03:23 |       |
|  11 |            INDEX RANGE SCAN              | AP_INVOICES_N2               |    11 |       |     3   (0)| 00:00:56 |       |
|  12 |           INDEX RANGE SCAN               | AP_INVOICE_DISTRIBUTIONS_N33 |     2 |       |     2   (0)| 00:00:37 |       |
|  13 |          TABLE ACCESS BY INDEX ROWID     | AP_INVOICE_DISTRIBUTIONS_ALL |     1 |    27 |     3   (0)| 00:00:56 |       |
|  14 |       TABLE ACCESS BY INDEX ROWID        | AP_INVOICES_ALL              |     1 |    42 |     2   (0)| 00:00:37 |       |
|  15 |        INDEX UNIQUE SCAN                 | AP_INVOICES_U1               |     1 |       |     1   (0)| 00:00:19 |       |
|  16 |      INDEX RANGE SCAN                    | AP_INVOICE_DISTRIBUTIONS_N33 |     1 |       |     2   (0)| 00:00:37 |       |
|  17 |       COUNT STOPKEY                      |                              |       |       |            |          |       |
|  18 |        TABLE ACCESS BY INDEX ROWID       | AP_INVOICE_DISTRIBUTIONS_ALL |     1 |    27 |     4   (0)| 00:01:14 |       |
|  19 |         INDEX RANGE SCAN                 | AP_INVOICE_DISTRIBUTIONS_N33 |     2 |       |     3   (0)| 00:00:56 |       |
|  20 |     TABLE ACCESS BY INDEX ROWID          | AP_INVOICE_DISTRIBUTIONS_ALL |     1 |    27 |     3   (0)| 00:00:56 |       |
|  21 |    NESTED LOOPS                          |                              |       |       |            |          |       |
|  22 |     NESTED LOOPS                         |                              |     1 |    17 |     6   (0)| 00:01:51 |       |
|  23 |      TABLE ACCESS BY INDEX ROWID         | AP_INVOICE_PAYMENTS_ALL      |     1 |    10 |     4   (0)| 00:01:14 |       |
|  24 |       INDEX RANGE SCAN                   | AP_INVOICE_PAYMENTS_N1       |     1 |       |     3   (0)| 00:00:56 |       |
|  25 |      INDEX UNIQUE SCAN                   | AP_CHECKS_U1                 |     1 |       |     1   (0)| 00:00:19 |       |
|  26 |     TABLE ACCESS BY INDEX ROWID          | AP_CHECKS_ALL                |     1 |     7 |     2   (0)| 00:00:37 |       |
|  27 |   NESTED LOOPS SEMI                      |                              |     1 |   102 |    25   (0)| 00:07:41 |       |
|  28 |    NESTED LOOPS                          |                              |     1 |   100 |    20   (0)| 00:06:09 |       |
|  29 |     NESTED LOOPS                         |                              |     1 |    67 |    18   (0)| 00:05:32 |       |
|  30 |      TABLE ACCESS BY INDEX ROWID         | AP_INVOICES_ALL              |     1 |    42 |    15   (0)| 00:04:37 |       |
|  31 |       INDEX RANGE SCAN                   | AP_INVOICES_N7               |    15 |       |     3   (0)| 00:00:56 |       |
|  32 |      TABLE ACCESS BY INDEX ROWID         | AP_INVOICE_PAYMENTS_ALL      |     1 |    25 |     3   (0)| 00:00:56 |       |
|  33 |       INDEX RANGE SCAN                   | AP_INVOICE_PAYMENTS_N1       |     1 |       |     2   (0)| 00:00:37 |       |
|  34 |     TABLE ACCESS BY INDEX ROWID          | AP_CHECKS_ALL                |     1 |    33 |     2   (0)| 00:00:37 |       |
|  35 |      INDEX UNIQUE SCAN                   | AP_CHECKS_U1                 |     1 |       |     1   (0)| 00:00:19 |       |
|  36 |    VIEW PUSHED PREDICATE                 | VW_SQ_1                      |     1 |     2 |     5   (0)| 00:01:33 |       |
|  37 |     NESTED LOOPS                         |                              |     1 |    20 |     5   (0)| 00:01:33 |       |
|  38 |      TABLE ACCESS BY INDEX ROWID         | AP_INVOICE_DISTRIBUTIONS_ALL |     1 |    11 |     4   (0)| 00:01:14 |       |
|  39 |       INDEX RANGE SCAN                   | AP_INVOICE_DISTRIBUTIONS_N33 |     2 |       |     3   (0)| 00:00:56 |       |
|  40 |      INDEX UNIQUE SCAN                   | AP_INVOICE_LINES_U1          |     1 |     9 |     1   (0)| 00:00:19 |       |
|  41 |   NESTED LOOPS                           |                              |       |       |            |          |       |
|  42 |    NESTED LOOPS                          |                              |     1 |   113 |  1825   (0)| 09:20:33 |       |
|  43 |     NESTED LOOPS                         |                              |     1 |    79 |  1822   (0)| 09:19:38 |       |
|  44 |      MERGE JOIN CARTESIAN                |                              |     1 |    50 |  1820   (0)| 09:19:01 |       |
|  45 |       TABLE ACCESS BY INDEX ROWID        | AP_INVOICES_ALL              |     1 |    27 |    15   (0)| 00:04:37 |       |
|  46 |        INDEX RANGE SCAN                  | AP_INVOICES_N7               |    15 |       |     3   (0)| 00:00:56 |       |
|  47 |       BUFFER SORT                        |                              | 17282 |   388K|  1805   (0)| 09:14:24 |       |
|  48 |        PARTITION LIST SINGLE             |                              | 17282 |   388K|  1805   (0)| 09:14:24 |   KEY |
|  49 |         TABLE ACCESS BY LOCAL INDEX ROWID| XLA_AE_HEADERS               | 17282 |   388K|  1805   (0)| 09:14:24 |     1 |
|  50 |          INDEX RANGE SCAN                | XLA_AE_HEADERS_N5            |  5445 |       |   100   (0)| 00:30:43 |     1 |
|  51 |      PARTITION LIST SINGLE               |                              |     1 |    29 |     2   (0)| 00:00:37 |   KEY |
|  52 |       TABLE ACCESS BY LOCAL INDEX ROWID  | XLA_TRANSACTION_ENTITIES     |     1 |    29 |     2   (0)| 00:00:37 |     1 |
|  53 |        INDEX UNIQUE SCAN                 | XLA_TRANSACTION_ENTITIES_U1  |     1 |       |     1   (0)| 00:00:19 |     1 |
|  54 |     PARTITION LIST SINGLE                |                              |     1 |       |     2   (0)| 00:00:37 |   KEY |
|  55 |      INDEX RANGE SCAN                    | XLA_AE_LINES_U1              |     1 |       |     2   (0)| 00:00:37 |     1 |
|  56 |    TABLE ACCESS BY LOCAL INDEX ROWID     | XLA_AE_LINES                 |     1 |    34 |     3   (0)| 00:00:56 |     1 |
|  57 |   NESTED LOOPS                           |                              |       |       |            |          |       |
|  58 |    NESTED LOOPS                          |                              |     1 |   151 |    30   (0)| 00:09:13 |       |
|  59 |     NESTED LOOPS                         |                              |     1 |   135 |    28   (0)| 00:08:37 |       |
|  60 |      NESTED LOOPS                        |                              |     1 |   101 |    25   (0)| 00:07:41 |       |
|  61 |       NESTED LOOPS                       |                              |     1 |    72 |    23   (0)| 00:07:04 |       |
|  62 |        NESTED LOOPS                      |                              |     1 |    43 |    18   (0)| 00:05:32 |       |
|  63 |         TABLE ACCESS BY INDEX ROWID      | AP_INVOICES_ALL              |     1 |    27 |    15   (0)| 00:04:37 |       |
|  64 |          INDEX RANGE SCAN                | AP_INVOICES_N7               |    15 |       |     3   (0)| 00:00:56 |       |
|  65 |         TABLE ACCESS BY INDEX ROWID      | AP_INVOICE_PAYMENTS_ALL      |     1 |    16 |     3   (0)| 00:00:56 |       |
|  66 |          INDEX RANGE SCAN                | AP_INVOICE_PAYMENTS_N1       |     1 |       |     2   (0)| 00:00:37 |       |
|  67 |        PARTITION LIST SINGLE             |                              |     1 |    29 |     5   (0)| 00:01:33 |   KEY |
|  68 |         TABLE ACCESS BY LOCAL INDEX ROWID| XLA_AE_HEADERS               |     1 |    29 |     5   (0)| 00:01:33 |     1 |
|  69 |          INDEX RANGE SCAN                | XLA_AE_HEADERS_N2            |     1 |       |     2   (0)| 00:00:37 |     1 |
|  70 |       PARTITION LIST SINGLE              |                              |     1 |    29 |     2   (0)| 00:00:37 |   KEY |
|  71 |        TABLE ACCESS BY LOCAL INDEX ROWID | XLA_TRANSACTION_ENTITIES     |     1 |    29 |     2   (0)| 00:00:37 |     1 |
|  72 |         INDEX UNIQUE SCAN                | XLA_TRANSACTION_ENTITIES_U1  |     1 |       |     1   (0)| 00:00:19 |     1 |
|  73 |      PARTITION LIST SINGLE               |                              |     1 |    34 |     3   (0)| 00:00:56 |   KEY |
|  74 |       TABLE ACCESS BY LOCAL INDEX ROWID  | XLA_AE_LINES                 |     1 |    34 |     3   (0)| 00:00:56 |     1 |
|  75 |        INDEX RANGE SCAN                  | XLA_AE_LINES_U1              |     1 |       |     2   (0)| 00:00:37 |     1 |
|  76 |     INDEX UNIQUE SCAN                    | AP_CHECKS_U1                 |     1 |       |     1   (0)| 00:00:19 |       |
|  77 |    TABLE ACCESS BY INDEX ROWID           | AP_CHECKS_ALL                |     1 |    16 |     2   (0)| 00:00:37 |       |
XLA_AE_HEADERS is a table partition
Regards,
Gaurav

Thanks for the prompt reply.
XLA_AE_HEADERS is a table partition and showing high cost on TABLE ACCESS BY LOCAL INDEX ROWID similarly XLA_TRANSACTION_ENTITIES is also a table partion
OWNER    SEGMENT_NAME                   SEGMENT_T BYTES/1024/1024
XLA      XLA_AE_HEADERS                 TABLE PAR            .125
XLA      XLA_AE_HEADERS                 TABLE PAR            .125
XLA      XLA_AE_HEADERS                 TABLE PAR        2014.375
XLA      XLA_AE_HEADERS                 TABLE PAR          4424.5
XLA      XLA_AE_HEADERS                 TABLE PAR            .125
XLA      XLA_AE_HEADERS                 TABLE PAR            .125
XLA      XLA_AE_HEADERS                 TABLE PAR            .125
XLA      XLA_AE_HEADERS                 TABLE PAR            .125
XLA      XLA_AE_HEADERS                 TABLE PAR            .125
XLA      XLA_AE_HEADERS                 TABLE PAR            .125
XLA      XLA_AE_HEADERS                 TABLE PAR            .125
XLA      XLA_AE_HEADERS                 TABLE PAR            .125
XLA      XLA_AE_HEADERS                 TABLE PAR            .125
XLA      XLA_AE_HEADERS                 TABLE PAR            .125
XLA      XLA_AE_HEADERS                 TABLE PAR            .125
XLA      XLA_AE_HEADERS                 TABLE PAR            .125
XLA      XLA_AE_HEADERS                 TABLE PAR            .125
XLA      XLA_AE_HEADERS                 TABLE PAR          10.125
XLA      XLA_AE_HEADERS                 TABLE PAR            .125

Similar Messages

  • Oracle 9.2 prefers Table Access Full over Local Index by rowid access

    There's this table that has phone call records (30 million per day) that is partitioned by month (using the date column) and stores the last 6 months.
    The primary key is date (varchar2 in yymmdd format) + call_id (a varchar2(18) with a format like this yyyymmdd+<3letters>+<sequentialnumber>)
    The partition is by range like this:
    PARTITION BY RANGE (FECHA)
    PARTITION P200804 VALUES LESS THAN ('080501')
    LOGGING
    NOCOMPRESS,
    If I run this query I get this plan
    SELECT FECHA, SENTIDOTRAFICO,GEOGRAFIAID,SWITCHID,TIPOTRAFICOID,COUNT(*)
    FROM GES_CDRS_RCNG_NEW
    WHERE FECHA BETWEEN '080801' AND '080825'
         AND TASACION IS NULL
         AND BORRADO IS NULL
    GROUP BY FECHA, SENTIDOTRAFICO,GEOGRAFIAID,SWITCHID,TIPOTRAFICOID
    Plan
    SELECT STATEMENT CHOOSECost: 78 K Bytes: 24 K Cardinality: 1 K           
         2 SORT GROUP BY Cost: 78 K Bytes: 24 K Cardinality: 1 K      
              1 TABLE ACCESS FULL GESTION.GES_CDRS_RCNG_NEW Cost: 43 K Bytes: 625 M Cardinality: 31 M Partition #: 2 Partitions accessed #5
    If I hint the primary key index using /*+INDEX(GES_CDRS_RCNG_NEW PK_CDRS_RCNG_NEW)*/
    I get a different plan
    Plan
    SELECT STATEMENT CHOOSECost: 954 K Bytes: 24 K Cardinality: 1 K                
         3 SORT GROUP BY Cost: 954 K Bytes: 24 K Cardinality: 1 K           
              2 TABLE ACCESS BY LOCAL INDEX ROWID GESTION.GES_CDRS_RCNG_NEW Cost: 918 K Bytes: 625 M Cardinality: 31 M Partition #: 2 Partitions accessed #5     
                   1 INDEX RANGE SCAN UNIQUE GESTION.PK_CDRS_RCNG_NEW Cost: 137 K Cardinality: 31 M Partition #: 3 Partitions accessed #5
    Looking at the cost, the full scan is way better, but this is obviously not the case. Why does this happen?
    This problem forces many querys on this table to use hints or force the index use by adding conditions to the where clause like this
    where fecha = '080801'
    and clave like '20080801%'
    when just by stating the date would be enough to choose the correct partition. It also messes up joins with other tables.
    The table is analized every month, it has statistics that claim: 237,981,000 rows, 3,222,677 blocks, GLOBAL STATS: YES, LAST ANALYZED: 15/10/2008 21:05:26, Average row length: 213.
    The partition envolved in this query has this stats: 32,520,520 rows, 442,715 blocks, analized on 27/08/2008 20:43:40
    The index has this stats: analized on 15/10/2008 21:35:32, Blevel: 3, leaf blocks: 1,056,410, distinct keys: 238,484,510.
    It is a local index and each partition has its own statistics.

    If I don't understand incorrectly the plan and the Predicater information, it seems the full scan version that costs less is actually doing a full scan from the biggining of the table (6 months) up to the 080825 date and the one using an index (hinted) does a better scan.
    without hint
    | Id  | Operation            |  Name              | Rows  | Bytes | Cost  | Pstart| Pstop |
    |   0 | SELECT STATEMENT     |                    |  1170 | 24570 | 78443 |       |       |
    |   1 |  SORT GROUP BY       |                    |  1170 | 24570 | 78443 |       |       |
    |*  2 |   TABLE ACCESS FULL  | GES_CDRS_RCNG_NEW  |    31M|   625M| 42579 |     5 |     5 |
    Predicate Information (identified by operation id):
       2 - filter("GES_CDRS_RCNG_NEW"."FECHA"<='080825')
    Note: cpu costing is offWith the hint:
    | Id  | Operation                          |  Name              | Rows  | Bytes | Cost  | Pstart| Pstop |
    |   0 | SELECT STATEMENT                   |                    |  1170 | 24570 |   953K|       |       |
    |   1 |  SORT GROUP BY                     |                    |  1170 | 24570 |   953K|       |       |
    |   2 |   TABLE ACCESS BY LOCAL INDEX ROWID| GES_CDRS_RCNG_NEW  |    31M|   625M|   918K|     5 |     5 |
    |*  3 |    INDEX RANGE SCAN                | PK_CDRS_RCNG_NEW   |    31M|       |   136K|     5 |     5 |
    Predicate Information (identified by operation id):
       3 - access("GES_CDRS_RCNG_NEW"."FECHA">='080801' AND "GES_CDRS_RCNG_NEW"."FECHA"<='080825')
    Note: cpu costing is off

  • How to make optimizer fetch and join values from Indexes, no table access.

    Hi All,
    i am having a query which is just checking the existence of the values according to some of the filter criteria, and involves two tables in join. and i want optimizer to find the existence i.e the reult of the query by only accessing indexes only, not to go through table scan using indexes. Is there any way so that i can modify my query or force the optimizer to do the same? below is the existing plan of the query in which its accessing tables using indexes, which causing bottleneck in my DB as these tables are bulky ones.
    Execution Plan
    Plan hash value: 1209914516
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
    | 0 | SELECT STATEMENT | | 1 | | 6 (17)| 00:00:01 | | |
    | 1 | SORT AGGREGATE | | 1 | | | | | |
    |* 2 | FILTER | | | | | | | |
    | 3 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | |
    | 4 | NESTED LOOPS | | 1 | 24 | 4 (25)| 00:00:01 | | |
    | 5 | SORT UNIQUE | | 1 | 10 | 2 (0)| 00:00:01 | | |
    | 6 | TABLE ACCESS BY INDEX ROWID | INVOICELINEDISB | 1 | 10 | 2 (0)| 00:00:01 | | |
    |* 7 | INDEX RANGE SCAN | IDX_INVLINEDISB_UOMCD | 1 | | 1 (0)| 00:00:01 | | |
    | 8 | PARTITION HASH ITERATOR | | 1 | 14 | 1 (0)| 00:00:01 | KEY | KEY |
    |* 9 | TABLE ACCESS BY GLOBAL INDEX ROWID| INVOICEHEADERDISB | 1 | 14 | 1 (0)| 00:00:01 | ROWID | ROWID |
    |* 10 | INDEX UNIQUE SCAN | P_INVOICEHEADERDISB_PART | 1 | | 0 (0)| 00:00:01 | KEY | KEY |
    Predicate Information (identified by operation id):
    2 - filter( EXISTS (SELECT 0 FROM "XIGNCMN"."INVOICEHEADERDISB" "INVOICEHEADERDISB","XIGNCMN"."INVOICELINEDISB"
    "INVOICELINEDISB" WHERE "INVOICELINEDISB"."UNITOFMEASURECD"='USD' AND
    "INVOICEHEADERDISB"."INVOICEPK"="INVOICELINEDISB"."INVOICEPK" AND "INVOICEHEADERDISB"."PAYPK"=8135488395))
    7 - access("INVOICELINEDISB"."UNITOFMEASURECD"='USD')
    9 - filter("INVOICEHEADERDISB"."PAYPK"=8135488395)
    10 - access("INVOICEHEADERDISB"."INVOICEPK"="INVOICELINEDISB"."INVOICEPK")
    Statistics
    0 recursive calls
    0 db block gets
    14 consistent gets
    0 physical reads
    0 redo size
    410 bytes sent via SQL*Net to client
    385 bytes received via SQL*Net from client

    Jonathan Lewis wrote:
    930254 wrote:
    Hi All,
    i am having a query which is just checking the existence of the values according to some of the filter criteria, and involves two tables in join. and i want optimizer to find the existence i.e the reult of the query by only accessing indexes only, not to go through table scan using indexes. Is there any way so that i can modify my query or force the optimizer to do the same? below is the existing plan of the query in which its accessing tables using indexes, which causing bottleneck in my DB as these tables are bulky ones.
    Execution Plan
    Plan hash value: 1209914516
    | Id  | Operation                              | Name                     | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
    |   0 | SELECT STATEMENT                       |                          |     1 |       |     6  (17)| 00:00:01 |       |       |
    |   1 |  SORT AGGREGATE                        |                          |     1 |       |            |          |       |       |
    |*  2 |   FILTER                               |                          |       |       |            |          |       |       |
    |   3 |    FAST DUAL                           |                          |     1 |       |     2   (0)| 00:00:01 |       |       |
    |   4 |    NESTED LOOPS                        |                          |     1 |    24 |     4  (25)| 00:00:01 |       |       |
    |   5 |     SORT UNIQUE                        |                          |     1 |    10 |     2   (0)| 00:00:01 |       |       |
    |   6 |      TABLE ACCESS BY INDEX ROWID       | INVOICELINEDISB          |     1 |    10 |     2   (0)| 00:00:01 |       |       |
    |*  7 |       INDEX RANGE SCAN                 | IDX_INVLINEDISB_UOMCD    |     1 |       |     1   (0)| 00:00:01 |       |       |
    |   8 |     PARTITION HASH ITERATOR            |                          |     1 |    14 |     1   (0)| 00:00:01 |   KEY |   KEY |
    |*  9 |      TABLE ACCESS BY GLOBAL INDEX ROWID| INVOICEHEADERDISB        |     1 |    14 |     1   (0)| 00:00:01 | ROWID | ROWID |
    |* 10 |       INDEX UNIQUE SCAN                | P_INVOICEHEADERDISB_PART |     1 |       |     0   (0)| 00:00:01 |   KEY |   KEY |
    Predicate Information (identified by operation id):
    2 - filter( EXISTS (SELECT 0 FROM "XIGNCMN"."INVOICEHEADERDISB" "INVOICEHEADERDISB","XIGNCMN"."INVOICELINEDISB"
    "INVOICELINEDISB" WHERE "INVOICELINEDISB"."UNITOFMEASURECD"='USD' AND
    "INVOICEHEADERDISB"."INVOICEPK"="INVOICELINEDISB"."INVOICEPK" AND "INVOICEHEADERDISB"."PAYPK"=8135488395))
    7 - access("INVOICELINEDISB"."UNITOFMEASURECD"='USD')
    9 - filter("INVOICEHEADERDISB"."PAYPK"=8135488395)
    10 - access("INVOICEHEADERDISB"."INVOICEPK"="INVOICELINEDISB"."INVOICEPK")
    The sort unique at line 5 is surprising, I can't think of an obvious reason why it should appear unless the optimizer is trying to do something very clever to work around a problem we can't see (such as a statistics error with the hash partitioned indexe).
    Assuming that the test would do better starting with invoiceheaderdisn.paypkl I have to ask if you have an index on INVOICELINEDISB(INVOICEPK).The optimizer's choice of driving table indeed looks odd. Could it be due to misleading statistics or plain bug or just a case of CBO preferring a non-partitioned table over partitioned table when deciding the driving table? I must admit this design does look odd as it appears INVOICEHEADERDISB is a parent table and INVOICELINEDISB is a child table but somehow the parent table has been partitioned (using hash partitioning, I assume) but the child table is not.
    However, once CBO has decided the driving table, the SORT UNIQUE is not quite surprising. Assuming optimizer knows that there is a parent-child relationship between INVOICEHEADERDISB and INVOICELINEDISB table (based on INVOICEPK column), CBO needs to access only INVOICEPK and UNITOFMEASURECD columns fron the INVOICELINEDISB table in order to process the join. It uses index range scan on UNITOFMEASURECD table in order to get (part of) the necessary data and then accesses INVOICELINEDISB table to get the values of INVOICEPK column. Being a child table, it is possible that the driving row source will contain duplicate values for INVOICEPK column but not necessarily sorted. As CBO knows that outer table (i.e. INVOICEHEADERDISB) has a PK on INVOICEPK column, each row in driving row source will have either 1 or 0 rows matching from outer table. It appears that CBO "decides" that by eliminating the duplicate values of the INVOICEPK from driving row source, it can reduce the number of times the INVOICEHEADERDISB table is accessed.
    Now I am not sure if CBO does all this (eliminating duplicates from driving row source) only because the outer table is partitioned.
    Coming back to OP's original question, I believe OP will have to change the index definitions in order to avoid table access for this query. But there has to be a strong and logical argument to make this kind of change for just one query.
    Hope this helps.

  • How improve performance on access path TABLE ACCESS BY INDEX ROWID ?

    I have table MOVEMENT with about 26millions entries,
    select rowid from movement xxx
    where
    xxx.sTransType > 0
    AND xxx.sDevice < 1000
    AND xxx.sDevice >= 0
    AND (bitand(xxx.sSaleFlag,1) = 0 AND bitand(xxx.sSaleFlag,4) = 0)
    AND xxx.sArtClassRef < 100
    and xxx.tActionTime BETWEEN TO_DATE('13-05-2011 08:08:34', 'dd-mm-yyyy hh24:mi:ss') AND to_date('13-05-2011 14:08:34', 'dd-mm-yyyy hh24:mi:ss') ;
    PLAN_TABLE_OUTPUT
    Plan hash value: 679628763
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    | 0 | SELECT STATEMENT | | 1 | 34 | 10102 (1)| 00:02:02 |
    |* 1 | TABLE ACCESS BY INDEX ROWID| MOVEMENT | 1 | 34 | 10102 (1)| 00:02:02 |
    |* 2 | INDEX RANGE SCAN | MOVATIME_IX | 18489 | | 51 (0)| 00:00:01 |
    Predicate Information (identified by operation id):
    1 - filter("XXX"."SARTCLASSREF"<100 AND BITAND("XXX"."SSALEFLAG",1)=0 AND
    BITAND("XXX"."SSALEFLAG",4)=0 AND "XXX"."STRANSTYPE">0 AND "XXX"."SDEVICE"<1000
    AND "XXX"."SDEVICE">=0)
    2 - access("XXX"."TACTIONTIME">=TO_DATE('2011-05-13 08:08:34', 'yyyy-mm-dd
    hh24:mi:ss') AND "XXX"."TACTIONTIME"<=TO_DATE('2011-05-13 14:08:34', 'yyyy-mm-dd
    hh24:mi:ss'))
    there is index on tActionTime - MOVATIME_IX
    This query returns 12203 rows, so I would anticipate this number in plan table in row with id 1 and column Rows
    Final question if it is possible to optimize this query and what are the next steps to do it?
    Thanks.

    >
    I thought that access path via ROWID's is the fastest way to get row
    >
    It is the fastest way to get the row - FROM THE TABLE.
    But the ROWIDs have to be gotten from the index. That is what the INDEX RANGE SCAN is doing. It is getting the ROWIDs needed and then the TABLE ACCESS BY INDEX ROWID is getting the rows.
    >
    I'am still confused with COST values, TABLE ACCESS BY INDEX ROWID has 200times higher cost than INDEX RANGE SCAN,
    >
    The index entries for a range scan are in order so they are very compact. The actual rows might be all over the place.
    Have you ever you a library? Not the online ones - I mean the old-fashioned kind that actually has books printed on paper?
    If the librarian asks you, her helper, to go get all books whose title begins with the letter 'B' how would you do it?
    You could go back to the stacks and look at every book on every shelf for books with titles' starting with 'B'. That is the same as a FULL TABLE SCAN.
    Or you could go to the card catalog, pull out the drawer (or drawers) that has 'B' on the label and look at the information on the card. Part of that information is the location of the actual book: section, stack; that is similar to the ROWID.
    The card catalog might get you to the right stack of books; then you have to search the stack sequentially to look for the book by name.
    A ROWID will get Oracle to the right block but then it has to find the right row.
    So the cost of getting ROWIDs from an index using a RANGE SCAN (where values are scanned in order) is a lot cheaper than actually getting the rows. The first two index entries needed might be right next to each other in order but the rows themselves might be far apart on the disk.

  • How to Improve Local Index Performance ??

    I need to store telecom CDR Data, which having following fields
    CDR_DATE => Date
    Telephone_Num=> Varchar2(20)
    A=> Varchar2(40)
    B=> Varchar2(10)
    The Input Data volume is very High.. At Present 100 Million/Day
    So i created the Oracle Partition Table with Date Range Partition.
    The application will run always one type query
    select * from CDR where Telephone_Num='&TNUM' AND CDR_DATE between JAN09 AND MAR09;
    Question1
    what will be Best way to create Index? Which can provide best performance and not degrade Daily Loading of Data.
    Question2- For this I created the LOCAL Index
    Create Index ABC ON CDR (CDR_DATE,Telephone_Num) LOCAL;
    The Data fetching is using the index but I can see in Trace, the count of CONSISTENT GETS & PHYSICAL READS are very High.
    So please suggest, Creating LOCAL INDEX is wise decision or not. Or any other way.
    Thanks in advance.
    Sumit
    Edited by: Sumit2 on Jul 31, 2010 6:27 PM

    Sumit2 wrote:
    The Input Data volume is very High.. At Present 100 Million/Day
    So i created the Oracle Partition Table with Date Range Partition.
    The application will run always one type query
    select * from CDR where Telephone_Num='&TNUM' AND CDR_DATE between JAN09 AND MAR09;
    Question1
    what will be Best way to create Index? Which can provide best performance and not degrade Daily Loading of Data.
    Question2- For this I created the LOCAL Index
    Create Index ABC ON CDR (CDR_DATE,Telephone_Num) LOCAL;
    The Data fetching is using the index but I can see in Trace, the count of CONSISTENT GETS & PHYSICAL READS are very High.
    You've created the index with the columns in the wrong order - your equality condition is on telephone number and the range-based condition is on the date, so you need the telephone number first in the index.
    In fact, if your query is always going to be for whole days, you might as well exclude the date column from the index because it adds no precision to the query.
    Another option to consider is to create the table as an index-organized table that starts with a primary key that (telephone number, cdr_date) so that all the data for a given telephone number is contained within a very small number of index leaf blocks. (However, if you rarely have more than a couple of calls per number per day then the supporting strategies for this approach will cost more than the benefit you get from building the data structure to match the query requirements.)
    As far as data loading is concerned, your best strategy is to look at playing games with local indexes and partition exchange.
    Regards
    Jonathan Lewis
    http://jonathanlewis.wordpress.com
    http://www.jlcomp.demon.co.uk
    To post code, statspack/AWR report, execution plans or trace files, start and end the section with the tag {noformat}{noformat} (lowercase, curly brackets, no spaces) so that the text appears in fixed format.
    There is a +"Preview"+ tab at the top of the text entry panel. Use this to check what your message will look like before you post the message. If it looks a complete mess you're unlikely to get a response. (Click on the +"Plain text"+ tab if you want to edit the text to tidy it up.)
    +"Science is more than a body of knowledge; it is a way of thinking"+
    +Carl Sagan+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           

  • Why optimizer select plan with higher cost?

    Why optimizer select plan with higher cost?
    SQL with hint:
    SELECT /*+ index(ordm ORDA_PK) */
    ordm.orders_id h_docid, ordm.customer_nr h_clientid,
    ordm.cl_doc_type_code h_doctype,
    ordm.cl_doc_status_code cl_doc_status_code,
    ordm.cl_external_error_code h_errorcode, ordm.sys_version_id h_version,
    ordm.doc_number po_number, ordm.curdate po_curdate,
    ordm.cl_currency_code po_curr,
    TO_CHAR (ordm.amount, 'FM999999999999990.00') po_amount,
    ordm.account_nr po_cust_accnum, ordm.customer_name po_cust_name,
    ordd.cl_currency_cust_code po_cust_curr,
    TO_CHAR (ordd.cust_rate, 'FM999999999990.0099999999') po_cust_rate,
    ordd.cust_confirm po_cust_conf, ordd.ben_name po_ben_name,
    ordd.ben_accnum po_ben_accnum,
    ordd.cl_external_payment_code po_cust_amk, ordd.ben_info po_ben_info,
    ordd.comments po_comments
    FROM FINIX_IB.orders_archive ordm, FINIX_IB.orders_archive_fields ordd
    WHERE ordm.orders_id = ordd.orders_id (+)
    AND ordm.orders_id = NVL (4353, ordm.orders_id)
    Execution Plan
    0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=4918 Card=1 Bytes=185)
    1 0 NESTED LOOPS (OUTER) (Cost=4918 Card=1 Bytes=185)
    2 1 TABLE ACCESS (BY INDEX ROWID) OF 'ORDERS_ARCHIVE' (TABLE) (Cost=4916 Card=1 Bytes=87)
    3 2 INDEX (FULL SCAN) OF 'ORDA_PK' (INDEX (UNIQUE)) (Cost=4915 Card=1)
    4 1 TABLE ACCESS (BY INDEX ROWID) OF 'ORDERS_ARCHIVE_FIELDS' (TABLE) (Cost=2 Card=1 Bytes=98)
    5 4 INDEX (RANGE SCAN) OF 'ORDAF_ORDA_FK' (INDEX) (Cost=1 Card=1)
    Statistics
    0 recursive calls
    0 db block gets
    4792 consistent gets
    4786 physical reads
    0 redo size
    1020 bytes sent via SQL*Net to client
    237 bytes received via SQL*Net from client
    2 SQL*Net roundtrips to/from client
    0 sorts (memory)
    0 sorts (disk)
    1 rows processed
    SQL without hint:
    Execution Plan
    0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=9675 Card=1 Bytes=185)
    1 0 NESTED LOOPS (OUTER) (Cost=9675 Card=1 Bytes=185)
    2 1 TABLE ACCESS (FULL) OF 'ORDERS_ARCHIVE' (TABLE) (Cost=9673 Card=1 Bytes=87)
    3 1 TABLE ACCESS (BY INDEX ROWID) OF 'ORDERS_ARCHIVE_FIELDS' (TABLE) (Cost=2 Card=1 Bytes=98)
    4 3 INDEX (RANGE SCAN) OF 'ORDAF_ORDA_FK' (INDEX) (Cost=1 Card=1)
    Statistics
    1 recursive calls
    0 db block gets
    39706 consistent gets
    39694 physical reads
    0 redo size
    1037 bytes sent via SQL*Net to client
    237 bytes received via SQL*Net from client
    2 SQL*Net roundtrips to/from client
    0 sorts (memory)
    0 sorts (disk)
    1 rows processed

    The way you are comparing costs, is not the right way, as Billy already told you. Only for one query, the cost of different access paths can be compared, as can be seen in a 10053 trace.
    However, your problem seems to arise from the fact that you use the NVL function in the predicate "ordm.orders_id = NVL (4353, ordm.orders_id)". The NVL function always evaluates both expressions, so it has to do a "ordm.orders_id = 4353" and a "ordm.orders_id = ordm.orders_id". This is why both alternatives will show a full scan on your orders_archive table cq. orda_pk index.
    You are probably suppling a bind variable to this statement which in some cases contains a null and in some other cases contains a number. If by any chance you always supply a number, then the solution is easy: drop the NVL function and change the predicate to "ordm.orders_id = :<your bind variable>". If not, then you have combined two queries into one, where both variants each have its own optimal plan, but they have to share their plan due to bind variable peeking.
    To solve this, I think you have two options:
    1) Make sure your statement is reparsed everytime. If your statement doesn't get executed often, this strategy might work. You might implement this by doing unnecessary dynamic sql.
    2) Split your query into two queries where one handles the constant number input and the other handles the null/no input.
    Below are some test results I used for research:
    SQL> create table orders_archive
      2  as
      3  select l orders_id, lpad('*',100,'*') filler from (select level l from dual connect by level <= 10000)
      4  /
    Tabel is aangemaakt.
    SQL> create table orders_archive_fields
      2  as
      3  select l field_id, l+500 orders_id, lpad('*',100,'*') filler from (select level l from dual connect by level <= 9000)
      4  /
    Tabel is aangemaakt.
    SQL> alter table orders_archive add constraint orda_pk primary key (orders_id)
      2  /
    Tabel is gewijzigd.
    SQL> alter table orders_archive_fields add constraint ordaf_pk primary key (field_id)
      2  /
    Tabel is gewijzigd.
    SQL> alter table orders_archive_fields add constraint ordaf_orda_fk foreign key (orders_id) references orders_archive(orders_id)
      2  /
    Tabel is gewijzigd.
    SQL> create index ordaf_orda_fk on orders_archive_fields(orders_id)
      2  /
    Index is aangemaakt.
    SQL> exec dbms_stats.gather_table_stats(user,'ORDERS_ARCHIVE',cascade=>true)
    PL/SQL-procedure is geslaagd.
    SQL> exec dbms_stats.gather_table_stats(user,'ORDERS_ARCHIVE_FIELDS',cascade=>true)
    PL/SQL-procedure is geslaagd.
    SQL> explain plan
      2  for
      3  SELECT /*+ index(ordm ORDA_PK) */
      4  ordm.orders_id h_docid, ordm.filler, ordd.filler
      5  FROM orders_archive ordm, orders_archive_fields ordd
      6  WHERE ordm.orders_id = ordd.orders_id (+)
      7  AND ordm.orders_id = NVL(4353,ordm.orders_id)
      8  /
    Uitleg is gegeven.
    SQL> select * from table(dbms_xplan.display)
      2  /
    PLAN_TABLE_OUTPUT
    | Id  | Operation                    |  Name                  | Rows  | Bytes | Cost (%CPU)|
    |   0 | SELECT STATEMENT             |                        |     1 |   209 |     8   (0)|
    |   1 |  NESTED LOOPS OUTER          |                        |     1 |   209 |     8   (0)|
    |   2 |   TABLE ACCESS BY INDEX ROWID| ORDERS_ARCHIVE         |     1 |   104 |     7   (0)|
    |*  3 |    INDEX FULL SCAN           | ORDA_PK                |     1 |       |    22   (5)|
    |   4 |   TABLE ACCESS BY INDEX ROWID| ORDERS_ARCHIVE_FIELDS  |     1 |   105 |     2  (50)|
    |*  5 |    INDEX RANGE SCAN          | ORDAF_ORDA_FK          |     1 |       |            |
    Predicate Information (identified by operation id):
       3 - filter("ORDM"."ORDERS_ID"=NVL(4353,"ORDM"."ORDERS_ID"))
       5 - access("ORDM"."ORDERS_ID"="ORDD"."ORDERS_ID"(+))
    17 rijen zijn geselecteerd.
    SQL> exec dbms_lock.sleep(1)
    PL/SQL-procedure is geslaagd.
    SQL> explain plan
      2  for
      3  SELECT
      4  ordm.orders_id h_docid, ordm.filler, ordd.filler
      5  FROM orders_archive ordm, orders_archive_fields ordd
      6  WHERE ordm.orders_id = ordd.orders_id (+)
      7  AND ordm.orders_id = NVL(4353,ordm.orders_id)
      8  /
    Uitleg is gegeven.
    SQL> select * from table(dbms_xplan.display)
      2  /
    PLAN_TABLE_OUTPUT
    | Id  | Operation                    |  Name                  | Rows  | Bytes | Cost (%CPU)|
    |   0 | SELECT STATEMENT             |                        |     1 |   209 |    47   (7)|
    |   1 |  NESTED LOOPS OUTER          |                        |     1 |   209 |    47   (7)|
    |*  2 |   TABLE ACCESS FULL          | ORDERS_ARCHIVE         |     1 |   104 |    46   (7)|
    |   3 |   TABLE ACCESS BY INDEX ROWID| ORDERS_ARCHIVE_FIELDS  |     1 |   105 |     2  (50)|
    |*  4 |    INDEX RANGE SCAN          | ORDAF_ORDA_FK          |     1 |       |            |
    Predicate Information (identified by operation id):
       2 - filter("ORDM"."ORDERS_ID"=NVL(4353,"ORDM"."ORDERS_ID"))
       4 - access("ORDM"."ORDERS_ID"="ORDD"."ORDERS_ID"(+))
    16 rijen zijn geselecteerd.So this shows I reproduced your situation. Because the decode function doesn't evaluate all its arguments, but evaluates the first argument to see which arguments to evaluate, you'll see different behaviour now.
    SQL> exec dbms_lock.sleep(1)
    PL/SQL-procedure is geslaagd.
    SQL> explain plan
      2  for
      3  SELECT
      4  ordm.orders_id h_docid, ordm.filler, ordd.filler
      5  FROM orders_archive ordm, orders_archive_fields ordd
      6  WHERE ordm.orders_id = ordd.orders_id (+)
      7  AND ordm.orders_id = decode(4353,null,ordm.orders_id,4353)
      8  /
    Uitleg is gegeven.
    SQL> select * from table(dbms_xplan.display)
      2  /
    PLAN_TABLE_OUTPUT
    | Id  | Operation                    |  Name                  | Rows  | Bytes | Cost (%CPU)|
    |   0 | SELECT STATEMENT             |                        |     1 |   209 |     3  (34)|
    |   1 |  NESTED LOOPS OUTER          |                        |     1 |   209 |     3  (34)|
    |   2 |   TABLE ACCESS BY INDEX ROWID| ORDERS_ARCHIVE         |     1 |   104 |     2  (50)|
    |*  3 |    INDEX UNIQUE SCAN         | ORDA_PK                |     1 |       |     2  (50)|
    |   4 |   TABLE ACCESS BY INDEX ROWID| ORDERS_ARCHIVE_FIELDS  |     1 |   105 |     2  (50)|
    |*  5 |    INDEX RANGE SCAN          | ORDAF_ORDA_FK          |     1 |       |            |
    Predicate Information (identified by operation id):
       3 - access("ORDM"."ORDERS_ID"=4353)
       5 - access("ORDM"."ORDERS_ID"="ORDD"."ORDERS_ID"(+))
    17 rijen zijn geselecteerd.
    SQL> exec dbms_lock.sleep(1)
    PL/SQL-procedure is geslaagd.
    SQL> explain plan
      2  for
      3  SELECT
      4  ordm.orders_id h_docid, ordm.filler, ordd.filler
      5  FROM orders_archive ordm, orders_archive_fields ordd
      6  WHERE ordm.orders_id = ordd.orders_id (+)
      7  AND ordm.orders_id = decode(null,null,ordm.orders_id,null)
      8  /
    Uitleg is gegeven.
    SQL> select * from table(dbms_xplan.display)
      2  /
    PLAN_TABLE_OUTPUT
    | Id  | Operation                    |  Name                  | Rows  | Bytes | Cost (%CPU)|
    |   0 | SELECT STATEMENT             |                        |     1 |   209 |    46   (5)|
    |   1 |  NESTED LOOPS OUTER          |                        |     1 |   209 |    46   (5)|
    |*  2 |   TABLE ACCESS FULL          | ORDERS_ARCHIVE         |     1 |   104 |    45   (5)|
    |   3 |   TABLE ACCESS BY INDEX ROWID| ORDERS_ARCHIVE_FIELDS  |     1 |   105 |     2  (50)|
    |*  4 |    INDEX RANGE SCAN          | ORDAF_ORDA_FK          |     1 |       |            |
    Predicate Information (identified by operation id):
       2 - filter("ORDM"."ORDERS_ID"="ORDM"."ORDERS_ID")
       4 - access("ORDM"."ORDERS_ID"="ORDD"."ORDERS_ID"(+))
    16 rijen zijn geselecteerd.So two different plans depending on the input.
    Regards,
    Rob.

  • INDEX UNIQUE SCAN instead of   INDEX FULL SCAN or TABLE ACCESS FULL

    I have calculated statistics in all tables and indexes
    I have a table and a view and when I put it
    SELECT *
    FROM TABLE_A A
    INNER JOIN VIEW_B B ON A.KEY_ID = B.PFK_KEY_ID          
    WHERE (B.FK_ID_XXX = 1)
    If I see the execution plan:
    In TABLE_A make a
    TABLE ACCESS BY INDEX ROWID
    INDEX UNIQUE SCAN (FIELD_A_TABLE_A_PK)
    It’s OK. I NEED IT (INDEX UNIQUE SCAN)
    But If I put
    SELECT A.Field_1, A.Field_2, A.Field_3, A.Field_4
    FROM TABLE_A A
    INNER JOIN VIEW_B B ON A.KEY_ID = B.PFK_KEY_ID          
    WHERE (B.FK_ID_XXX = 1)
    In table A make a TABLE ACCESS FULL.
    Then If I put:
    SELECT /*+ INDEX(A FIELD_A_TABLE_A_PK) */ A.Field_1, A.Field_2, A.Field_3, A.Field_4
    FROM TABLE_A A
    INNER JOIN VIEW_B B ON A.KEY_ID = B.PFK_KEY_ID          
    WHERE (B.FK_ID_XXX = 1)
    If I see the execution plan:
    In TABLE_A make a
    TABLE ACCESS BY INDEX ROWID
    INDEX UNIQUE SCAN (FIELD_A_TABLE_A_PK)
    It’s OK. I NEED IT (INDEX UNIQUE SCAN)
    Finally, If I put other tables and views in the query (I NEED IT)
    For example:
    SELECT /*+ INDEX(A FIELD_A_TABLE_A_PK) */ A.Field_1, A.Field_2, A.Field_3, A.Field_4
    FROM TABLE_A A
    INNER JOIN VIEW_B B ON A.KEY_ID = B.PFK_KEY_ID          
    INNER JOIN TABLE_C….
    LEFT JOIN VIEW_D….
    WHERE (B.FK_ID_XXX = 1)
    If I see the execution plan:
    In TABLE_A make a
    TABLE ACCESS BY INDEX ROWID
    INDEX FULL SCAN (FIELD_A_TABLE_A_PK)
    I need INDEX UNIQUE SCAN instead of INDEX FULL SCAN or TABLE ACCESS FULL.
    How can obtain it?
    What happens???
    Thanks!

    Notice the difference in cardinality between your two select statements:
    SELECT STATEMENT, GOAL = ALL_ROWS Cost=5 Cardinality=1
    SELECT STATEMENT, GOAL = ALL_ROWS Cost=10450 Cardinality=472161Apparently since the optimizer believed the first statement was going to return one row, it used an index. But in the second statement it believed it was going to return nearly the whole table (didn't you say it had around 500k rows?). Hence full table scan.

  • Local index vs global index in partitioned tables

    Hi,
    I want to know the differences between a global and a local index.
    I'm working with partitioned tables about 10 millons rows and 40 partitions.
    I know that when your table is partitioned and your index non-partitioned is possible that
    some database operations make your index unusable and you have tu rebuid it, for example
    when yo truncate a partition your global index results unusable, is there any other operation
    that make the global index unusable??
    I think that the advantage of a global index is that takes less space than a local and is easier to rebuild,
    and the advantage of a local index is that is more effective resolving a query isn't it???
    Any advice and help about local vs global index in partitioned tables will be greatly apreciatted.
    Thanks in advance

    here is the documentation -> http://download-uk.oracle.com/docs/cd/B19306_01/server.102/b14220/partconc.htm#sthref2570
    In general, you should use global indexes for OLTP applications and local indexes for data warehousing or DSS applications. Also, whenever possible, you should try to use local indexes because they are easier to manage. When deciding what kind of partitioned index to use, you should consider the following guidelines in order:
    1. If the table partitioning column is a subset of the index keys, use a local index. If this is the case, you are finished. If this is not the case, continue to guideline 2.
    2. If the index is unique, use a global index. If this is the case, you are finished. If this is not the case, continue to guideline 3.
    3. If your priority is manageability, use a local index. If this is the case, you are finished. If this is not the case, continue to guideline 4.
    4. If the application is an OLTP one and users need quick response times, use a global index. If the application is a DSS one and users are more interested in throughput, use a local index.
    Kind regards,
    Tonguç

  • What happens to Existing index after table partition and created with local index

    Hi guys,
    desc part id  number, name  varchar2(100), salary  number
    In an existing table  PART  i am  adding 1 more column DATASEQ NUMBER. i am asked to partition the table part based on dataseq.now the table is created with this logic
    create table part( id  number, name  varchar2(100), salary  number, DATASEQ  number) partition by list(dataseq) (partition PART_INITIAL  values (1));
    Suggestionn required. since  the table is partitioned based on DATASEQ i am asked to add local index on dataseq. i have added local index to dataseq create index idx on part(dataseq) LOCAL; Now my question is  already there is existing index is for the column ID and salary.
    1)  IDX for  dataseq is created locally so that it will have partition on each partition on the main table. Please tell me what happens to the existing index on the column ID and salary.. will it again created in local?
    Please suggest
    S

    Hi,
    first of all, in reality "partition a table" means create a new table a migrate existing data there (although theoretically you can use dbms_redefinition to partition an existing table -- however, it's just doing the same thing behind the scenes). This means that you also get to decide what to do with the indexes -- which indexes will be local, which will be global (you can also re-evaluate some of existing indexes and decide that they're not really needed).
    Second of all, the choice of partitioning key looks odd. Partitioning is a data manageability technique more than anything else, so in order to benefit from it you need to find a good partitioning key. A recently added column named "data_seq" doesn't look like a good candidate. Can you provide more details about this column and why it was chosen as a partitioning key?
    I suspect that whoever suggested this partitioning scheme is making a huge mistake. A non-partitioned table is much better in all aspects (including manageability and performance) than wrongly partitioned one.
    Best regards,
    Nikolay

  • Using index in a query return few records than full table access

    Today we have an issue with a query, when it use the ok index the returned are not all records that apply to where clause condition.
    See bellow
    explain plan for
    select * from movdb.zan_m03 where
    M00AF = TO_DATE('11/01/28','YY/MM/DD') AND
    M00za = 10 AND
    m00AC = 50 AND
    M00AD between 136906 and 136999
    SELECT * FROM TABLE(dbms_xplan.display);
    PLAN_TABLE_OUTPUT
    Plan hash value: 1882720105
    | Id | Operation | Name |
    | 0 | SELECT STATEMENT | |
    | 1 | TABLE ACCESS BY INDEX ROWID| ZAN_M03 |
    |* 2 | INDEX RANGE SCAN | PK_ZAN_M03 |
    Predicate Information (identified by operation id):
    PLAN_TABLE_OUTPUT
    2 - access("M00AF"=TO_DATE('11/01/28','YY/MM/DD') AND "M00ZA"=10 AND
    "M00AC"=50 AND "M00AD">=136906 AND "M00AD"<=137141)
    filter("M00AD"<=137141 AND "M00AD">=136906)
    Note
    - rule based optimizer used (consider using cbo)
    20 rows selected.
    The query above return only one row insted 1579 record that apply to this conditions.
    When forcing a full table acess with a hint, the query return all records that apply, the 1579 record.
    select /*+ FULL(zan_m03) */ M00AF, M00za, m00AC , M00AD from movdb.zan_m03 where
    M00AF = TO_DATE('11/01/28','YY/MM/DD') AND
    M00za = 10 AND
    m00AC = 50 AND
    M00AD between 136906 and 137141
    Can you help me to identify what's happening?
    I am with Oracle 10g R2 10.2.0.4 standard edition
    the statistics are up to date
    the opitimizer_mode are rule, but altering in session level to all_rows happens the same issue.
    Nothing about corruption in the alert log.
    Thanks in advance
    Regards
    Cristiano

    Yes the query are the same and correct restriction for where clause are M00AD between 136906 and 137141.
    I've pasted, by mistake, another test query
    The corrects are:
    select M00AF, M00za, m00AC , M00AD from movdb.zan_m03 where
    M00AF = TO_DATE('11/01/28','YY/MM/DD') AND
    M00za = 10 AND
    m00AC = 50 AND
    M00AD between 136906 and 137141
    This use pk index and return one row
    select /*+ FULL(zan_m03) */ M00AF, M00za, m00AC , M00AD from movdb.zan_m03 where
    M00AF = TO_DATE('11/01/28','YY/MM/DD') AND
    M00za = 10 AND
    m00AC = 50 AND
    M00AD between 136906 and 137141
    This does a full table access and return 1579 records
    I´ve been searching for wrong results bugs on my oracle support, but not found one that mentions something like our issue.
    I checked the dba_tables and dba indexes and the number of rows are different, and I think this would be the same because it's is a pk.
    Look this
    SQL> select NUM_ROWS from dba_tables where table_name = 'ZAN_M03'
    2 /
    NUM_ROWS
    228527878
    select NUM_ROWS from dba_indexes where index_name = 'PK_ZAN_M03';
    SQL> select NUM_ROWS from dba_indexes where index_name = 'PK_ZAN_M03';
    NUM_ROWS
    217510185
    Is normal a index for pk having much fewer rows than table? I think not, but not sure.
    Again
    Thanks in advance
    Regards
    Cristiano

  • Table access by index rowid taking more time

    Hi All
    I've a query like
    update tab1
      set col1 = ( select col2 from
                           tab2 
                    where tab1.id = tab2.id) table 1 has arnd 10,000 rows
    table 2 has arnd 1,700,000 rows and has a primay key on column id.
    This query is taking around 20 secs to execute. I checked the xplan and most of time taken for table access by index rowid.
    Could you please suggest what can be the reason for this. (Can it be the clustering factor or something else)
    I checked the stats for the tab2, its just three days old.
    Regards
    Ashwani

    >
    table 1 has arnd 10,000 rows
    table 2 has arnd 1,700,000 rows and has a primay key on column id.
    This query is taking around 20 secs to execute. I checked the xplan and most of time taken for table access by index rowid.
    Could you please suggest what can be the reason for this. (Can it be the clustering factor or something else)
    I checked the stats for the tab2, its just three days old.
    >
    If you checked the xplan why haven't you posted it so we can look at it? Then we could see what table is being accessed by index rowid. Presumably it is table 2 but we the plan would eliminate the need to make assumptions.
    The clustering factor could be a factor. You haven't told us how table1 is being accessed. All rows are being updated so a full table scann is most likely but again the plan would actually show the access.
    Did you query the dictionary to see what the clustering factor is? Post the results of that
    SQL> select index_name, leaf_blocks, avg_leaf_blocks_per_key, avg_data_blocks_per_key, clustering_factor, distinct_keys
    2 from dba_indexes
    3 where owner = 'schema'
    4 and index_name in ('index_b','index_a');

  • Problem in accessing mseg table using MSEG~M Index.

    Hi Experts,
    I am facing problem in accessing mseg table using MSEG~M Index. I used same sequence of fields and i tried with mandt field also. but it is not taking the Index and it is going for TImeout ABAP dump.
    This are my codes used in different ways
    1.  SELECT  mjahr
             bwart
             matnr
             lifnr
             dmbtr
             kostl
             aufnr
             bukrs
             FROM mseg CLIENT SPECIFIED INTO TABLE t_mseg2
                      WHERE mandt EQ sy-mandt      AND
                            matnr NE SPACE         AND
                            werks EQ p_werks       AND
                            lgort NE '0000'        AND
                            bwart IN (122,201,262) AND
                            sobkz NE '0'
                            %_HINTS ORACLE 'INDEX("MSEG" "MSEG~M")'.
    2.   SELECT  mjahr
             bwart
             matnr
             lifnr
             dmbtr
             kostl
             aufnr
             bukrs
             FROM mseg  INTO TABLE t_mseg2
                      WHERE matnr NE SPACE         AND
                            werks EQ p_werks       AND
                            lgort NE '0000'        AND
                            bwart IN (122,201,262) AND
                            sobkz NE '0'
                            %_HINTS ORACLE 'INDEX("MSEG" "MSEG~M")'.
    3.   SELECT  mjahr
             bwart
             matnr
             lifnr
             dmbtr
             kostl
             aufnr
             bukrs
             FROM mseg INTO TABLE t_mseg2
                      WHERE matnr NE SPACE         AND
                            werks EQ p_werks       AND
                            lgort NE '0000'        AND
                            bwart IN (122,201,262) AND
                            sobkz NE '0'.                   
    The above all code is not at all taking the index in Quality server .but in Development it is taking .In Quality server it is reading all datas without using the index and going Timeout ABAP dmup
    Please, Suggest me some solutions.
    Thanks in Advance.
    Regards,
    Nandha

    Hi,
    Without NE also not working out. i am facing same problem still.
    SELECT  bwart
             matnr
             lifnr
             dmbtr
             kostl
             aufnr
             FROM mseg CLIENT SPECIFIED INTO TABLE t_mseg
                      WHERE mandt EQ sy-mandt      AND
                            werks EQ p_werks       AND
                            bwart IN (122,201,262) AND
                            mjahr EQ p_year        AND
                            bukrs EQ p_cc
                            %_HINTS ORACLE 'INDEX("MSEG" "MSEG~M")'.
    Please,check and help me out from this issue.
    Regards,
    Nandha

  • HOW TO CREATE LOCAL INDEX ON BIG PARTITION TABLE

    Dear All,
    I have one big table 450GB stored on 9 partitions and same partitions I have created for the index. Now the problem is when i am trying to create local index it took one and half day and is still going on...
    is there any shortest way to create local index on this table easily.
    Database version is 11.2.0.1.0
    INDEX SCRIPT IS
    CREATE INDEX INDEX_SPACE0_IX_LOCAL ON FINANCE (END_TIME)
    INITRANS 2 MAXTRANS
    255
    LOCAL ( PARTITION INDEX_SPACE01
    LOGGING
    NOCOMPRESS
    TABLESPACE INDEX_SPACE01
    PCTFREE 5 INITRANS 2 MAXTRANS 255 STORAGE (INITIAL 1M MINEXTENTS 1 MAXEXTENTS
    2147483645 BUFFER_POOL
    DEFAULT), PARTITION INDEX_SPACE02
    LOGGING
    NOCOMPRESS
    TABLESPACE INDEX_SPACE02 PCTFREE
    5 INITRANS 2 MAXTRANS 255 STORAGE (INITIAL 1M MINEXTENTS 1 MAXEXTENTS
    2147483645 BUFFER_POOL DEFAULT),
    PARTITION INDEX_SPACE03
    LOGGING
    NOCOMPRESS
    TABLESPACE
    INDEX_SPACE03
    PCTFREE 5 INITRANS 2 MAXTRANS 255 STORAGE (INITIAL 1M MINEXTENTS 1 MAXEXTENTS
    2147483645 BUFFER_POOL DEFAULT),
    PARTITION INDEX_SPACE04
    LOGGING
    NOCOMPRESS
    TABLESPACE
    INDEX_SPACE04 PCTFREE 5 INITRANS 2 MAXTRANS 255 STORAGE (INITIAL 1M MINEXTENTS
    1 MAXEXTENTS
    2147483645 BUFFER_POOL DEFAULT),
    PARTITION INDEX_SPACE05
    LOGGING
    NOCOMPRESS
    TABLESPACE
    INDEX_SPACE05 PCTFREE 5 INITRANS 2 MAXTRANS 255 STORAGE (INITIAL 1M MINEXTENTS
    1 MAXEXTENTS 2147483645 BUFFER_POOL DEFAULT),
    PARTITION INDEX_SPACE06
    LOGGING
    NOCOMPRESS
    TABLESPACE INDEX_SPACE06 PCTFREE 5 INITRANS 2
    MAXTRANS 255 STORAGE (INITIAL 1M MINEXTENTS 1 MAXEXTENTS 2147483645 BUFFER_POOL
    DEFAULT),
    PARTITION INDEX_SPACE07
    LOGGING
    NOCOMPRESS
    TABLESPACE INDEX_SPACE07 PCTFREE
    5 INITRANS 2
    MAXTRANS 255 STORAGE (INITIAL 1M MINEXTENTS 1 MAXEXTENTS 2147483645 BUFFER_POOL
    DEFAULT),
    PARTITION INDEX_SPACE08
    LOGGING
    NOCOMPRESS
    TABLESPACE INDEX_SPACE08 PCTFREE
    5 INITRANS 2 MAXTRANS 255 STORAGE (INITIAL 1M MINEXTENTS 1 MAXEXTENTS
    2147483645
    BUFFER_POOL DEFAULT),
    PARTITION INDEX_SPACE09
    LOGGING
    NOCOMPRESS
    TABLESPACE
    INDEX_SPACE09 PCTFREE 5 INITRANS 2 MAXTRANS 255 STORAGE (INITIAL 1M MINEXTENTS
    1 MAXEXTENTS 2147483645 BUFFER_POOL
    DEFAULT))
    NOPARALLEL;
    Thanks in advance......
    Thanks,
    Edited by: sherkhan on Aug 24, 2011 3:36 AM
    Edited by: sherkhan on Aug 24, 2011 3:49 AM

    Have you verified that 'n' Index partition segments have got created so far ? (they would apepar as TEMPORARY segments only till the full index creation is completed). Have you monitored the session statistics and waits and confirmed that it is not waiting on something horrible ?
    A CREATE INDEX can well be NOLOGGING instead of LOGGING. It could also use PARALLEL but I always recommend setting it back to NOPARALLEL immediately after the CREATE is completed.
    You can also "quickly" build an empty index and then gradually create (i.e. build) each partition
    CREATE INDEX INDEX_SPACE0_IX_LOCAL  .........  UNUSABLE ;
    ALTER INDEX INDEX_SPACE0_IX_LOCAL REBUILD PARTITION PARTITION INDEX_SPACE01;
    ALTER INDEX INDEX_SPACE0_IX_LOCAL REBUILD PARTITION PARTITION INDEX_SPACE02;
    ...Hemant K Chitale

  • Pagination query help needed for large table - force a different index

    I'm using a slight modification of the pagination query from over at Ask Tom's: [http://www.oracle.com/technology/oramag/oracle/07-jan/o17asktom.html]
    Mine looks like this when fetching the first 100 rows of all members with last name Smith, ordered by join date:
    SELECT members.*
    FROM members,
        SELECT RID, rownum rnum
        FROM
            SELECT rowid as RID
            FROM members
            WHERE last_name = 'Smith'
            ORDER BY joindate
        WHERE rownum <= 100
    WHERE rnum >= 1
             and RID = members.rowidThe difference between this and the one at Ask Tom's is that my innermost query just returns the ROWID. Then in the outermost query we join the ROWIDs returned to the members table, after we have pruned the ROWIDs down to only the chunk of 100 we want. This makes it MUCH faster (verifiably) on our large tables, as it is able to use the index on the innermost query (well... read on).
    The problem I have is this:
    SELECT rowid as RID
    FROM members
    WHERE last_name = 'Smith'
    ORDER BY joindateThis will use the index for the predicate column (last_name) instead of the unique index I have defined for the joindate column (joindate, sequence). (Verifiable with explain plan). It is much slower this way on a large table. So I can hint it using either of the following methods:
    SELECT /*+ index(members, joindate_idx) */ rowid as RID
    FROM members
    WHERE last_name = 'Smith'
    ORDER BY joindate
    SELECT /*+ first_rows(100) */ rowid as RID
    FROM members
    WHERE last_name = 'Smith'
    ORDER BY joindateEither way, it now uses the index of the ORDER BY column (joindate_idx), so now it is much faster as it does not have to do a sort (remember, VERY large table, millions of records). So that seems good. But now, on my outermost query, I join the rowid with the meaningful columns of data from the members table, as commented below:
    SELECT members.*      -- Select all data from members table
    FROM members,           -- members table added to FROM clause
        SELECT RID, rownum rnum
        FROM
            SELECT /*+ index(members, joindate_idx) */ rowid as RID   -- Hint is ignored now that I am joining in the outer query
            FROM members
            WHERE last_name = 'Smith'
            ORDER BY joindate
        WHERE rownum <= 100
    WHERE rnum >= 1
            and RID = members.rowid           -- Merge the members table on the rowid we pulled from the inner queriesOnce I do this join, it goes back to using the predicate index (last_name) and has to perform the sort once it finds all matching values (which can be a lot in this table, there is high cardinality on some columns).
    So my question is, in the full query above, is there any way I can get it to use the ORDER BY column for indexing to prevent it from having to do a sort? The join is what causes it to revert back to using the predicate index, even with hints. Remove the join and just return the ROWIDs for those 100 records and it flies, even on 10 million records.
    It'd be great if there was some generic hint that could accomplish this, such that if we change the table/columns/indexes, we don't need to change the hint (the FIRST_ROWS hint is a good example of this, while the INDEX hint is the opposite), but any help would be appreciated. I can provide explain plans for any of the above if needed.
    Thanks!

    Lakmal Rajapakse wrote:
    OK here is an example to illustrate the advantage:
    SQL> set autot traceonly
    SQL> select * from (
    2  select a.*, rownum x  from
    3  (
    4  select a.* from aoswf.events a
    5  order by EVENT_DATETIME
    6  ) a
    7  where rownum <= 1200
    8  )
    9  where x >= 1100
    10  /
    101 rows selected.
    Execution Plan
    Plan hash value: 3711662397
    | Id  | Operation                      | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT               |            |  1200 |   521K|   192   (0)| 00:00:03 |
    |*  1 |  VIEW                          |            |  1200 |   521K|   192   (0)| 00:00:03 |
    |*  2 |   COUNT STOPKEY                |            |       |       |            |          |
    |   3 |    VIEW                        |            |  1200 |   506K|   192   (0)| 00:00:03 |
    |   4 |     TABLE ACCESS BY INDEX ROWID| EVENTS     |   253M|    34G|   192   (0)| 00:00:03 |
    |   5 |      INDEX FULL SCAN           | EVEN_IDX02 |  1200 |       |     2   (0)| 00:00:01 |
    Predicate Information (identified by operation id):
    1 - filter("X">=1100)
    2 - filter(ROWNUM<=1200)
    Statistics
    0  recursive calls
    0  db block gets
    443  consistent gets
    0  physical reads
    0  redo size
    25203  bytes sent via SQL*Net to client
    281  bytes received via SQL*Net from client
    8  SQL*Net roundtrips to/from client
    0  sorts (memory)
    0  sorts (disk)
    101  rows processed
    SQL>
    SQL>
    SQL> select * from aoswf.events a, (
    2  select rid, rownum x  from
    3  (
    4  select rowid rid from aoswf.events a
    5  order by EVENT_DATETIME
    6  ) a
    7  where rownum <= 1200
    8  ) b
    9  where x >= 1100
    10  and a.rowid = rid
    11  /
    101 rows selected.
    Execution Plan
    Plan hash value: 2308864810
    | Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT            |            |  1200 |   201K|   261K  (1)| 00:52:21 |
    |   1 |  NESTED LOOPS               |            |  1200 |   201K|   261K  (1)| 00:52:21 |
    |*  2 |   VIEW                      |            |  1200 | 30000 |   260K  (1)| 00:52:06 |
    |*  3 |    COUNT STOPKEY            |            |       |       |            |          |
    |   4 |     VIEW                    |            |   253M|  2895M|   260K  (1)| 00:52:06 |
    |   5 |      INDEX FULL SCAN        | EVEN_IDX02 |   253M|  4826M|   260K  (1)| 00:52:06 |
    |   6 |   TABLE ACCESS BY USER ROWID| EVENTS     |     1 |   147 |     1   (0)| 00:00:01 |
    Predicate Information (identified by operation id):
    2 - filter("X">=1100)
    3 - filter(ROWNUM<=1200)
    Statistics
    8  recursive calls
    0  db block gets
    117  consistent gets
    0  physical reads
    0  redo size
    27539  bytes sent via SQL*Net to client
    281  bytes received via SQL*Net from client
    8  SQL*Net roundtrips to/from client
    0  sorts (memory)
    0  sorts (disk)
    101  rows processed
    Lakmal (and OP),
    Not sure what advantage you are trying to show here. But considering that we are talking about pagination query here and order of records is important, your 2 queries will not always generate output in same order. Here is the test case:
    SQL> select * from v$version ;
    BANNER
    Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
    PL/SQL Release 10.2.0.1.0 - Production
    CORE     10.2.0.1.0     Production
    TNS for Linux: Version 10.2.0.1.0 - Production
    NLSRTL Version 10.2.0.1.0 - Production
    SQL> show parameter optimizer
    NAME                                 TYPE        VALUE
    optimizer_dynamic_sampling           integer     2
    optimizer_features_enable            string      10.2.0.1
    optimizer_index_caching              integer     0
    optimizer_index_cost_adj             integer     100
    optimizer_mode                       string      ALL_ROWS
    optimizer_secure_view_merging        boolean     TRUE
    SQL> show parameter pga
    NAME                                 TYPE        VALUE
    pga_aggregate_target                 big integer 103M
    SQL> create table t nologging as select * from all_objects where 1 = 2 ;
    Table created.
    SQL> create index t_idx on t(last_ddl_time) nologging ;
    Index created.
    SQL> insert /*+ APPEND */ into t (owner, object_name, object_id, created, last_ddl_time) select owner, object_name, object_id, created, sysdate - dbms_random.value(1, 100) from all_objects order by dbms_random.random;
    40617 rows created.
    SQL> commit ;
    Commit complete.
    SQL> exec dbms_stats.gather_table_stats(user, 'T', cascade=>true);
    PL/SQL procedure successfully completed.
    SQL> select object_id, object_name, created from t, (select rid, rownum rn from (select rowid rid from t order by created desc) where rownum <= 1200) t1 where rn >= 1190 and t.rowid = t1.rid ;
    OBJECT_ID OBJECT_NAME                    CREATED
         47686 ALL$OLAP2_JOIN_KEY_COLUMN_USES 28-JUL-2009 08:08:39
         47672 ALL$OLAP2_CUBE_DIM_USES        28-JUL-2009 08:08:39
         47681 ALL$OLAP2_CUBE_MEASURE_MAPS    28-JUL-2009 08:08:39
         47682 ALL$OLAP2_FACT_LEVEL_USES      28-JUL-2009 08:08:39
         47685 ALL$OLAP2_AGGREGATION_USES     28-JUL-2009 08:08:39
         47692 ALL$OLAP2_CATALOGS             28-JUL-2009 08:08:39
         47665 ALL$OLAPMR_FACTTBLKEYMAPS      28-JUL-2009 08:08:39
         47688 ALL$OLAP2_DIM_LEVEL_ATTR_MAPS  28-JUL-2009 08:08:39
         47689 ALL$OLAP2_DIM_LEVELS_KEYMAPS   28-JUL-2009 08:08:39
         47669 ALL$OLAP9I2_HIER_DIMENSIONS    28-JUL-2009 08:08:39
         47666 ALL$OLAP9I1_HIER_DIMENSIONS    28-JUL-2009 08:08:39
    11 rows selected.
    SQL> select object_id, object_name, last_ddl_time from t, (select rid, rownum rn from (select rowid rid from t order by last_ddl_time desc) where rownum <= 1200) t1 where rn >= 1190 and t.rowid = t1.rid ;
    OBJECT_ID OBJECT_NAME                    LAST_DDL_TIME
         11749 /b9fe5b99_OraRTStatementComman 06-FEB-2010 03:43:49
         13133 oracle/jdbc/driver/OracleLog$3 06-FEB-2010 03:45:44
         37534 com/sun/mail/smtp/SMTPMessage  06-FEB-2010 03:46:14
         36145 /4e492b6f_SerProfileToClassErr 06-FEB-2010 03:11:09
         26815 /7a628fb8_DefaultHSBChooserPan 06-FEB-2010 03:26:55
         16695 /2940a364_RepIdDelegator_1_3   06-FEB-2010 03:38:17
         36539 sun/io/ByteToCharMacHebrew     06-FEB-2010 03:28:57
         14044 /d29b81e1_OldHeaders           06-FEB-2010 03:12:12
         12920 /25f8f3a5_BasicSplitPaneUI     06-FEB-2010 03:11:06
         42266 SI_GETCLRHSTGRFTR              06-FEB-2010 03:40:20
         15752 /2f494dce_JDWPThreadReference  06-FEB-2010 03:09:31
    11 rows selected.
    SQL> select object_id, object_name, last_ddl_time from (select t1.*, rownum rn from (select * from t order by last_ddl_time desc) t1 where rownum <= 1200) where rn >= 1190 ;
    OBJECT_ID OBJECT_NAME                    LAST_DDL_TIME
         37534 com/sun/mail/smtp/SMTPMessage  06-FEB-2010 03:46:14
         13133 oracle/jdbc/driver/OracleLog$3 06-FEB-2010 03:45:44
         11749 /b9fe5b99_OraRTStatementComman 06-FEB-2010 03:43:49
         42266 SI_GETCLRHSTGRFTR              06-FEB-2010 03:40:20
         16695 /2940a364_RepIdDelegator_1_3   06-FEB-2010 03:38:17
         36539 sun/io/ByteToCharMacHebrew     06-FEB-2010 03:28:57
         26815 /7a628fb8_DefaultHSBChooserPan 06-FEB-2010 03:26:55
         14044 /d29b81e1_OldHeaders           06-FEB-2010 03:12:12
         36145 /4e492b6f_SerProfileToClassErr 06-FEB-2010 03:11:09
         12920 /25f8f3a5_BasicSplitPaneUI     06-FEB-2010 03:11:06
         15752 /2f494dce_JDWPThreadReference  06-FEB-2010 03:09:31
    11 rows selected.
    SQL> select object_id, object_name, last_ddl_time from t, (select rid, rownum rn from (select rowid rid from t order by last_ddl_time desc) where rownum <= 1200) t1 where rn >= 1190 and t.rowid = t1.rid order by last_ddl_time desc ;
    OBJECT_ID OBJECT_NAME                    LAST_DDL_TIME
         37534 com/sun/mail/smtp/SMTPMessage  06-FEB-2010 03:46:14
         13133 oracle/jdbc/driver/OracleLog$3 06-FEB-2010 03:45:44
         11749 /b9fe5b99_OraRTStatementComman 06-FEB-2010 03:43:49
         42266 SI_GETCLRHSTGRFTR              06-FEB-2010 03:40:20
         16695 /2940a364_RepIdDelegator_1_3   06-FEB-2010 03:38:17
         36539 sun/io/ByteToCharMacHebrew     06-FEB-2010 03:28:57
         26815 /7a628fb8_DefaultHSBChooserPan 06-FEB-2010 03:26:55
         14044 /d29b81e1_OldHeaders           06-FEB-2010 03:12:12
         36145 /4e492b6f_SerProfileToClassErr 06-FEB-2010 03:11:09
         12920 /25f8f3a5_BasicSplitPaneUI     06-FEB-2010 03:11:06
         15752 /2f494dce_JDWPThreadReference  06-FEB-2010 03:09:31
    11 rows selected.
    SQL> set autotrace traceonly
    SQL> select object_id, object_name, last_ddl_time from t, (select rid, rownum rn from (select rowid rid from t order by last_ddl_time desc) where rownum <= 1200) t1 where rn >= 1190 and t.rowid = t1.rid order by last_ddl_time desc
      2  ;
    11 rows selected.
    Execution Plan
    Plan hash value: 44968669
    | Id  | Operation                       | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT                |       |  1200 | 91200 |   180   (2)| 00:00:03 |
    |   1 |  SORT ORDER BY                  |       |  1200 | 91200 |   180   (2)| 00:00:03 |
    |*  2 |   HASH JOIN                     |       |  1200 | 91200 |   179   (2)| 00:00:03 |
    |*  3 |    VIEW                         |       |  1200 | 30000 |    98   (0)| 00:00:02 |
    |*  4 |     COUNT STOPKEY               |       |       |       |            |          |
    |   5 |      VIEW                       |       | 40617 |   475K|    98   (0)| 00:00:02 |
    |   6 |       INDEX FULL SCAN DESCENDING| T_IDX | 40617 |   793K|    98   (0)| 00:00:02 |
    |   7 |    TABLE ACCESS FULL            | T     | 40617 |  2022K|    80   (2)| 00:00:01 |
    Predicate Information (identified by operation id):
       2 - access("T".ROWID="T1"."RID")
       3 - filter("RN">=1190)
       4 - filter(ROWNUM<=1200)
    Statistics
              1  recursive calls
              0  db block gets
            348  consistent gets
              0  physical reads
              0  redo size
           1063  bytes sent via SQL*Net to client
            385  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              1  sorts (memory)
              0  sorts (disk)
             11  rows processed
    SQL> select object_id, object_name, last_ddl_time from (select t1.*, rownum rn from (select * from t order by last_ddl_time desc) t1 where rownum <= 1200) where rn >= 1190 ;
    11 rows selected.
    Execution Plan
    Plan hash value: 882605040
    | Id  | Operation                | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT         |      |  1200 | 62400 |    80   (2)| 00:00:01 |
    |*  1 |  VIEW                    |      |  1200 | 62400 |    80   (2)| 00:00:01 |
    |*  2 |   COUNT STOPKEY          |      |       |       |            |          |
    |   3 |    VIEW                  |      | 40617 |  1546K|    80   (2)| 00:00:01 |
    |*  4 |     SORT ORDER BY STOPKEY|      | 40617 |  2062K|    80   (2)| 00:00:01 |
    |   5 |      TABLE ACCESS FULL   | T    | 40617 |  2062K|    80   (2)| 00:00:01 |
    Predicate Information (identified by operation id):
       1 - filter("RN">=1190)
       2 - filter(ROWNUM<=1200)
       4 - filter(ROWNUM<=1200)
    Statistics
              0  recursive calls
              0  db block gets
            343  consistent gets
              0  physical reads
              0  redo size
           1063  bytes sent via SQL*Net to client
            385  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              1  sorts (memory)
              0  sorts (disk)
             11  rows processed
    SQL> select object_id, object_name, last_ddl_time from t, (select rid, rownum rn from (select rowid rid from t order by last_ddl_time desc) where rownum <= 1200) t1 where rn >= 1190 and t.rowid = t1.rid ;
    11 rows selected.
    Execution Plan
    Plan hash value: 168880862
    | Id  | Operation                      | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT               |       |  1200 | 91200 |   179   (2)| 00:00:03 |
    |*  1 |  HASH JOIN                     |       |  1200 | 91200 |   179   (2)| 00:00:03 |
    |*  2 |   VIEW                         |       |  1200 | 30000 |    98   (0)| 00:00:02 |
    |*  3 |    COUNT STOPKEY               |       |       |       |            |          |
    |   4 |     VIEW                       |       | 40617 |   475K|    98   (0)| 00:00:02 |
    |   5 |      INDEX FULL SCAN DESCENDING| T_IDX | 40617 |   793K|    98   (0)| 00:00:02 |
    |   6 |   TABLE ACCESS FULL            | T     | 40617 |  2022K|    80   (2)| 00:00:01 |
    Predicate Information (identified by operation id):
       1 - access("T".ROWID="T1"."RID")
       2 - filter("RN">=1190)
       3 - filter(ROWNUM<=1200)
    Statistics
              0  recursive calls
              0  db block gets
            349  consistent gets
              0  physical reads
              0  redo size
           1063  bytes sent via SQL*Net to client
            385  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
             11  rows processed
    SQL> select object_id, object_name, last_ddl_time from (select t1.*, rownum rn from (select * from t order by last_ddl_time desc) t1 where rownum <= 1200) where rn >= 1190 order by last_ddl_time desc ;
    11 rows selected.
    Execution Plan
    Plan hash value: 882605040
    | Id  | Operation           | Name | Rows     | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT      |     |  1200 | 62400 |    80   (2)| 00:00:01 |
    |*  1 |  VIEW                |     |  1200 | 62400 |    80   (2)| 00:00:01 |
    |*  2 |   COUNT STOPKEY       |     |     |     |          |          |
    |   3 |    VIEW            |     | 40617 |  1546K|    80   (2)| 00:00:01 |
    |*  4 |     SORT ORDER BY STOPKEY|     | 40617 |  2062K|    80   (2)| 00:00:01 |
    |   5 |      TABLE ACCESS FULL      | T     | 40617 |  2062K|    80   (2)| 00:00:01 |
    Predicate Information (identified by operation id):
       1 - filter("RN">=1190)
       2 - filter(ROWNUM<=1200)
       4 - filter(ROWNUM<=1200)
    Statistics
         175  recursive calls
           0  db block gets
         388  consistent gets
           0  physical reads
           0  redo size
           1063  bytes sent via SQL*Net to client
         385  bytes received via SQL*Net from client
           2  SQL*Net roundtrips to/from client
           4  sorts (memory)
           0  sorts (disk)
          11  rows processed
    SQL> set autotrace off
    SQL> spool offAs you will see, the join query here has to have an ORDER BY clause at the end to ensure that records are correctly sorted. You can not rely on optimizer choosing NESTED LOOP join method and, as above example shows, when optimizer chooses HASH JOIN, oracle is free to return rows in no particular order.
    The query that does not involve join always returns rows in the desired order. Adding an ORDER BY does add a step in the plan for the query using join but does not affect the other query.

  • "Tables are not using indexes"-Please help

    We have a new database , version
    Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bi
    PL/SQL Release 10.2.0.1.0 - Production
    CORE 10.2.0.1.0 Production
    TNS for IBM/AIX RISC System/6000: Version 10.2.0.1.0 - Productio
    NLSRTL Version 10.2.0.1.0 - Production
    We have created Indexes for the tables and analysed the table. Problem is , non of the tables are using indexes. Explain paln for the sql queries are showing full table scan.
    Kindly let me know any parameter I have to change or is there any setttings needed on database level?
    Thanks in advance.
    Regards,
    Chotu

    What is your optimizer mode?
    Another question why you want to use indexes? Use of indexes depends,
    Here is a simple example
    test@>ed
    Wrote file afiedt.buf
      1  explain plan for
      2  select c.cname from mytable c, mytable1 m
      3* where c.cname=m.cname
    test@>/
    Explained.
    test@>SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
    PLAN_TABLE_OUTPUT
    Plan hash value: 2460944079
    | Id  | Operation         | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT  |              |     8 |    64 |     1   (0)| 00:00:01 |
    |   1 |  NESTED LOOPS     |              |     8 |    64 |     1   (0)| 00:00:01 |
    |   2 |   INDEX FULL SCAN | C_MYTAB_IDX  |     8 |    32 |     1   (0)| 00:00:01 |
    |*  3 |   INDEX RANGE SCAN| C_MYTAB1_IDX |     1 |     4 |     0   (0)| 00:00:01 |
    Predicate Information (identified by operation id):
       3 - access("C"."CNAME"="M"."CNAME")
    15 rows selected.
    test@>explain plan for
      2  select * from mytable;
    Explained.
    test@>SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
    PLAN_TABLE_OUTPUT
    Plan hash value: 1229213413
    | Id  | Operation         | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
    |   0 | SELECT STATEMENT  |         |     8 |    32 |     3   (0)| 00:00:01 |
    |   1 |  TABLE ACCESS FULL| MYTABLE |     8 |    32 |     3   (0)| 00:00:01 |
    8 rows selected.As you see MYTABLE has an index but it not always uses that index it depends on the need.
    sql queries are showing full table scan this is a not a curse. So unless you are having some problem. You should not change queries only because to avoid full table scans, there is no rule that indexes should always be used in every case.
    Adith

Maybe you are looking for

  • I Just Want My Update!!!!

    I have been in and out of the forums all day trying to figure out why i cant update my Iphone... I keep getting the "Your Iphone is being set up for software update" and then A 1602 ERROR!!!! I have tried apples trouble shooting and i have tried some

  • ITunes Match not syncing album by year in Music app

    I have been cleaning up my iTunes library, on my MBP. While importing some new songs and editing some old ones, the albums are sorting correctly by year in iTunes, but not in the Music app in iOS. I edited the year info for all the tracks in the albu

  • Replicated scheme - data format

    Hi all      I was doing memory size experiment on coherence. I was wondering if someone has answer to the following case:      I am doing this investigation using Replicated cache scheme.      I want to load 3 million id/value pairs, into a named cac

  • TS3745 What do I do with the import folder once it is on my desktop? Can I delete it?

    I followed the advice to stop getting the "6 pictures were found and not imported message."  I moved the import file in my iPhoto folder to the desktop. Now what do I do with the folder, can I delete it?

  • Sort photo in iPad

    Hi, my name is massimo. My father bought an ipad. Unfortunately he doesn't have a mac but,an (horrible) PC with Windows XP SP3. I can't order the photos into ipad. I tried some guides, but in spite of having changed the EXIF metadata inside each pict