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 clientJonathan 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 PMSumit2 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 processedThe 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 advancehere 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
SHi,
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
CristianoYes 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,
NandhaHi,
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 AMHave 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,
ChotuWhat 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?
-
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