Cbo plan
Pls tell me how the execution plan execute in CBO.
from RBO Is right to left.
I am runing one query is RBO as well as CBO Plan is different
sequence of table access is different.
Thanks
Reena
Hi,
which version of Oracle are you runnning,
In CBO the optimizer will determine the driving table. The CBO will determine upon the COST which will be the driving table which will be derermined by the INDEXES, the Statistics of the table and other parameters.
Where as in RBO the table from the right in the FORM clause will be the driving table.
thanks
Similar Messages
-
I am having one batch job in which query fatching data from various tables and inserting in one table.
It's taking 3-4 hours. On generating explain plan i come to know that query taking more time due to one outer join between one view(say V1) and large table(say T1).
V1.Column(+) =T1.Column1 || '-' || T1.Column2
If i remove this outer join it will improve but according to need i can't do it.
It's oracle8i and its using rule based only
I am planning to create 2 Indexed. 1 on T1.Column1 and other T1.Column2. or any other suggestion from you guys.
It's very urgent i need to do it in 2 days. Please any one help me out
Thanks in advance
ChetanChetanS wrote:
This is my tkprof result
call count cpu elapsed disk query current rows
Parse 1 12.24 12.26 0 0 2 0
Execute 1 0.01 0.02 0 3 9 0
Fetch 438 48.54 153.05 43263 917910 241 438000
total 440 60.79 165.33 43263 917913 252 438000
See below explain plan
you find more cost due to above joinI'm not sure how to interpret your posts. A few comments:
1. You said you're using 8i with rule based optimization. But now you're talking about cost and the plan shows a cost, too. So it looks more like a CBO plan.
2. If you say that "If i remove this outer join it will improve but according to need i can't do it.", what do you mean exactly?
- Turn the the outer join into an inner join?
- Remove the join clause completely?
And what do you mean by "it will improve"? Does it perform better, or do you get simply a lower cost returned by EXPLAIN PLAN?
3. The plan looks convoluted. There are REMOTE objects involved and the DUAL table is referenced multiple times, so it might a very good idea to share the actual query code used. If required, mask the table/view names and replace them with "table1/2/3" etc.
Note that the optimizer often does a suboptimal job when REMOTE objects are involved, so may be this is one of the root causes of your performance issues.
4. Use the \ tag before and after text that should be formatted in fixed font for better readability. Use the "Quote" button in the message editor to see how I did it here.
Regards,
Randolf
Oracle related stuff blog:
http://oracle-randolf.blogspot.com/
SQLTools++ for Oracle (Open source Oracle GUI for Windows):
http://www.sqltools-plusplus.org:7676/
http://sourceforge.net/projects/sqlt-pp/ -
Oracle 11.1.0.7.
spfile - optimizer_mode = ALL_ROWS. optimizer_features_enable = 11.1.0.7.
Auto stats gathering jobs are all enabled. So everything should be all CBO all the way.
Some queries were mysteriously slow on Friday. Digging into AWR stats finally revealed that a SQL statement (sql_id) had spawned a plan_hash_value that was the culprit. It was doing a full table scan on a large table and consuming a lot of CPU/IO. Dumping out everything AWR knows about this SQL using
select * from table(dbms_xplan.display_awr('45knuy45ha5f2',NULL,NULL,'ADVANCED'))Pored over the output and sure enough, the "bad" plan_hash_value was using the FTS and the Note in the output said "rule based optimizer used (consider using cbo)".
I couldn't believe my eyes. Why in the world did that one child cursor use the RBO?
Any ideas?Karthick - No. The query is coming from a application so the query and session parameters are fixed. As AWR shows, the query was executed dozens of times and all the plan_hash_values for the same sql_id use CBO, just this one bad apple used the RBO. Why?
Hoek - Yes, I read all of Kerry Osborne's excellent blog entries, that's how I narrowed down the problem to this particular sql_id. But it doesn't talk about WHY a particular query would use the RBO. The most common culprit, bind variable peeking, may cause the plan to flip between 2 CBO plans but it shouldn't cause the RBO to be used.
Martin - That's what I thought too but all objects used in the query do have stats. Since the Oracle auto-stats job/task is running daily, stats are always up-to-date. Here are all the optimizer* parameters in the spfile.
This is really frustrating.
optimizer_features_enable 11.1.0.7
optimizer_mode ALL_ROWS
optimizer_index_cost_adj 100
optimizer_index_caching 0
optimizer_dynamic_sampling 2
optimizer_secure_view_merging TRUE
optimizer_use_pending_statistics FALSE
optimizer_capture_sql_plan_baselines FALSE
optimizer_use_sql_plan_baselines TRUE
optimizer_use_invisible_indexes FALSE[Oracle Support is looking into it but they usually ask for a 10046 trace and we can't provide that because AWR doesn't capture that and the issue is not reproducible at-will] -
CBO generating different plans for the same data in similar Environments
Hi All
I have been trying to compare an SQL from 2 different but similar environments build of the same hardware specs .The issue I am facing is environment A, the query executes in less than 2 minutes with plan mostly showing full table scans and hash join whereas in environment B(problematic), it times out after 2 hours with an error of unable to extend table space . The statistics are up to date in both environments for both tables and indexes . System parameters are exactly similar(default oracle for except for multiblock_read_count ).
Both Environment have same db parameter for db_file_multiblock_read_count(16), optimizer(refer below),hash_area_size (131072),pga_aggregate_target(1G),db_block_size(8192) etc . SREADTIM, MREADTIM, CPUSPEED, MBRC are all null in aux_stats in both environment because workload was never collected i believe.
Attached is details about the SQL with table stats, SQL and index stats my main concern is CBO generating different plans for the similar data and statistics and same hardware and software specs. Is there any thing else I should consider .I generally see environment B being very slow and always plans tend to nested loops and index scan whereas what we really need is a sensible FTS in many cases. One of the very surprising thing is METER_CONFIG_HEADER below which has just 80 blocks of data is being asked for index scan.
show parameter optimizer
optimizer_dynamic_sampling integer 2
optimizer_features_enable string 10.2.0.4
optimizer_index_caching integer 0
optimizer_index_cost_adj integer 100
optimizer_mode string ALL_ROWS
optimizer_secure_view_merging boolean TRUE
**Environment**
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
PL/SQL Release 10.2.0.4.0 - Production
CORE 10.2.0.4.0 Production
TNS for Solaris: Version 10.2.0.4.0 - Production
NLSRTL Version 10.2.0.4.0 - Production
Note: : There are slight difference in the no of records in the attached sheet.However, I wanted to tell that i have tested with exact same data and was getting similar results but I couldn't retain the data untill collecting the details in the attachment
TEST1 COMPARE TABLE LEVE STATS used by CBO
ENVIRONMENT A
TABLE_NAME NUM_ROWS BLOCKS LAST_ANALYZED
ASSET 3607425 167760 5/02/2013 22:11
METER_CONFIG_HEADER 3658 80 5/01/2013 0:07
METER_CONFIG_ITEM 32310 496 5/01/2013 0:07
NMI 1899024 33557 18/02/2013 10:55
REGISTER 4830153 101504 18/02/2013 9:57
SDP_LOGICAL_ASSET 1607456 19137 18/02/2013 15:48
SDP_LOGICAL_REGISTER 5110781 78691 18/02/2013 9:56
SERVICE_DELIVERY_POINT 1425890 42468 18/02/2013 13:54
ENVIRONMENT B
TABLE_NAME NUM_ROWS BLOCKS LAST_ANALYZED
ASSET 4133939 198570 16/02/2013 10:02
METER_CONFIG_HEADER 3779 80 16/02/2013 10:55
METER_CONFIG_ITEM 33720 510 16/02/2013 10:55
NMI 1969000 33113 16/02/2013 10:58
REGISTER 5837874 120104 16/02/2013 11:05
SDP_LOGICAL_ASSET 1788152 22325 16/02/2013 11:06
SDP_LOGICAL_REGISTER 6101934 91088 16/02/2013 11:07
SERVICE_DELIVERY_POINT 1447589 43804 16/02/2013 11:11
TEST ITEM 2 COMPARE INDEX STATS used by CBO
ENVIRONMENT A
TABLE_NAME INDEX_NAME UNIQUENESS BLEVEL LEAF_BLOCKS DISTINCT_KEYS AVG_LEAF_BLOCKS_PER_KEY AVG_DATA_BLOCKS_PER_KEY CLUSTERING_FACTOR NUM_ROWS
ASSET IDX_AST_DEVICE_CATEGORY_SK NONUNIQUE 2 9878 67 147 12982 869801 3553095
ASSET IDX_A_SAPINTLOGDEV_SK NONUNIQUE 2 7291 2747 2 639 1755977 3597916
ASSET SYS_C00102592 UNIQUE 2 12488 3733831 1 1 3726639 3733831
METER_CONFIG_HEADER SYS_C0092052 UNIQUE 1 12 3670 1 1 3590 3670
METER_CONFIG_ITEM SYS_C0092074 UNIQUE 1 104 32310 1 1 32132 32310
NMI IDX_NMI_ID NONUNIQUE 2 6298 844853 1 2 1964769 1965029
NMI IDX_NMI_ID_NK NONUNIQUE 2 6701 1923072 1 1 1922831 1923084
NMI IDX_NMI_STATS NONUNIQUE 1 106 4 26 52 211 211
REGISTER REG_EFFECTIVE_DTM NONUNIQUE 2 12498 795 15 2899 2304831 4711808
REGISTER SYS_C00102653 UNIQUE 2 16942 5065660 1 1 5056855 5065660
SDP_LOGICAL_ASSET IDX_SLA_SAPINTLOGDEV_SK NONUNIQUE 2 3667 1607968 1 1 1607689 1607982
SDP_LOGICAL_ASSET IDX_SLA_SDP_SK NONUNIQUE 2 3811 668727 1 2 1606204 1607982
SDP_LOGICAL_ASSET SYS_C00102665 UNIQUE 2 5116 1529606 1 1 1528136 1529606
SDP_LOGICAL_REGISTER SYS_C00102677 UNIQUE 2 17370 5193638 1 1 5193623 5193638
SERVICE_DELIVERY_POINT IDX_SDP_NMI_SK NONUNIQUE 2 4406 676523 1 2 1423247 1425890
SERVICE_DELIVERY_POINT IDX_SDP_SAP_INT_NMI_SK NONUNIQUE 2 7374 676523 1 2 1458238 1461108
SERVICE_DELIVERY_POINT SYS_C00102687 UNIQUE 2 4737 1416207 1 1 1415022 1416207
ENVIRONMENT B
TABLE_NAME INDEX_NAME UNIQUENESS BLEVEL LEAF_BLOCKS DISTINCT_KEYS AVG_LEAF_BLOCKS_PER_KEY AVG_DATA_BLOCKS_PER_KEY CLUSTERING_FACTOR NUM_ROWS
ASSET IDX_AST_DEVICE_CATEGORY_SK NONUNIQUE 2 8606 121 71 16428 1987833 4162257
ASSET IDX_A_SAPINTLOGDEV_SK NONUNIQUE 2 8432 1780146 1 1 2048170 4162257
ASSET SYS_C00116157 UNIQUE 2 13597 4162263 1 1 4158759 4162263
METER_CONFIG_HEADER SYS_C00116570 UNIQUE 1 12 3779 1 1 3734 3779
METER_CONFIG_ITEM SYS_C00116592 UNIQUE 1 107 33720 1 1 33459 33720
NMI IDX_NMI_ID NONUNIQUE 2 6319 683370 1 2 1970460 1971313
NMI IDX_NMI_ID_NK NONUNIQUE 2 6597 1971293 1 1 1970771 1971313
NMI IDX_NMI_STATS NONUNIQUE 1 98 48 2 4 196 196
REGISTER REG_EFFECTIVE_DTM NONUNIQUE 2 15615 1273 12 2109 2685924 5886582
REGISTER SYS_C00116748 UNIQUE 2 19533 5886582 1 1 5845565 5886582
SDP_LOGICAL_ASSET IDX_SLA_SAPINTLOGDEV_SK NONUNIQUE 2 4111 1795084 1 1 1758441 1795130
SDP_LOGICAL_ASSET IDX_SLA_SDP_SK NONUNIQUE 2 4003 674249 1 2 1787987 1795130
SDP_LOGICAL_ASSET SYS_C004520 UNIQUE 2 5864 1795130 1 1 1782147 1795130
SDP_LOGICAL_REGISTER SYS_C004539 UNIQUE 2 20413 6152850 1 1 6073059 6152850
SERVICE_DELIVERY_POINT IDX_SDP_NMI_SK NONUNIQUE 2 3227 660649 1 2 1422572 1447803
SERVICE_DELIVERY_POINT IDX_SDP_SAP_INT_NMI_SK NONUNIQUE 2 6399 646257 1 2 1346948 1349993
SERVICE_DELIVERY_POINT SYS_C00128706 UNIQUE 2 4643 1447946 1 1 1442796 1447946
TEST ITEM 3 COMPARE PLANS
ENVIRONMENT A
Plan hash value: 4109575732
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 13 | 2067 | | 135K (2)| 00:27:05 |
| 1 | HASH UNIQUE | | 13 | 2067 | | 135K (2)| 00:27:05 |
|* 2 | HASH JOIN | | 13 | 2067 | | 135K (2)| 00:27:05 |
|* 3 | HASH JOIN | | 6 | 900 | | 135K (2)| 00:27:04 |
|* 4 | HASH JOIN ANTI | | 1 | 137 | | 135K (2)| 00:27:03 |
|* 5 | TABLE ACCESS BY INDEX ROWID| NMI | 1 | 22 | | 5 (0)| 00:00:01 |
| 6 | NESTED LOOPS | | 1 | 131 | | 95137 (2)| 00:19:02 |
|* 7 | HASH JOIN | | 1 | 109 | | 95132 (2)| 00:19:02 |
|* 8 | TABLE ACCESS FULL | ASSET | 36074 | 1021K| | 38553 (2)| 00:07:43 |
|* 9 | HASH JOIN | | 90361 | 7059K| 4040K| 56578 (2)| 00:11:19 |
|* 10 | HASH JOIN | | 52977 | 3414K| 2248K| 50654 (2)| 00:10:08 |
|* 11 | HASH JOIN | | 39674 | 1782K| | 40101 (2)| 00:08:02 |
|* 12 | TABLE ACCESS FULL | REGISTER | 39439 | 1232K| | 22584 (2)| 00:04:32 |
|* 13 | TABLE ACCESS FULL | SDP_LOGICAL_REGISTER | 4206K| 56M| | 17490 (2)| 00:03:30 |
|* 14 | TABLE ACCESS FULL | SERVICE_DELIVERY_POINT | 675K| 12M| | 9412 (2)| 00:01:53 |
|* 15 | TABLE ACCESS FULL | SDP_LOGICAL_ASSET | 1178K| 15M| | 4262 (2)| 00:00:52 |
|* 16 | INDEX RANGE SCAN | IDX_NMI_ID_NK | 2 | | | 2 (0)| 00:00:01 |
| 17 | VIEW | | 39674 | 232K| | 40101 (2)| 00:08:02 |
|* 18 | HASH JOIN | | 39674 | 1046K| | 40101 (2)| 00:08:02 |
|* 19 | TABLE ACCESS FULL | REGISTER | 39439 | 500K| | 22584 (2)| 00:04:32 |
|* 20 | TABLE ACCESS FULL | SDP_LOGICAL_REGISTER | 4206K| 56M| | 17490 (2)| 00:03:30 |
|* 21 | TABLE ACCESS FULL | METER_CONFIG_HEADER | 3658 | 47554 | | 19 (0)| 00:00:01 |
|* 22 | TABLE ACCESS FULL | METER_CONFIG_ITEM | 7590 | 68310 | | 112 (2)| 00:00:02 |
Predicate Information (identified by operation id):
2 - access("METER_CONFIG_HEADER_SK"="METER_CONFIG_HEADER_SK")
3 - access("NETWORK_TARIFF_CD"="NETWORK_TARIFF_CD")
4 - access("SERVICE_DELIVERY_POINT_SK"="TMP"."SERVICE_DELIVERY_POINT_SK")
5 - filter("ROW_CURRENT_IND"='Y' AND ("NMI_STATUS_CD"='A' OR "NMI_STATUS_CD"='D'))
7 - access("ASSET_CD"="EQUIP_CD" AND "SAP_INT_LOG_DEVICE_SK"="SAP_INT_LOG_DEVICE_SK")
8 - filter("ROW_CURRENT_IND"='Y')
9 - access("SERVICE_DELIVERY_POINT_SK"="SERVICE_DELIVERY_POINT_SK")
10 - access("SERVICE_DELIVERY_POINT_SK"="SERVICE_DELIVERY_POINT_SK")
11 - access("SAP_INT_LOGICAL_REGISTER_SK"="SAP_INT_LOGICAL_REGISTER_SK")
12 - filter("REGISTER_TYPE_CD"='C' AND (SUBSTR("REGISTER_ID_CD",1,1)='4' OR
SUBSTR("REGISTER_ID_CD",1,1)='5' OR SUBSTR("REGISTER_ID_CD",1,1)='6') AND "ROW_CURRENT_IND"='Y')
13 - filter("ROW_CURRENT_IND"='Y')
14 - filter("ROW_CURRENT_IND"='Y')
15 - filter("ROW_CURRENT_IND"='Y')
16 - access("NMI_SK"="NMI_SK")
18 - access("SAP_INT_LOGICAL_REGISTER_SK"="SAP_INT_LOGICAL_REGISTER_SK")
19 - filter("REGISTER_TYPE_CD"='C' AND (SUBSTR("REGISTER_ID_CD",1,1)='1' OR
SUBSTR("REGISTER_ID_CD",1,1)='2' OR SUBSTR("REGISTER_ID_CD",1,1)='3') AND "ROW_CURRENT_IND"='Y')
20 - filter("ROW_CURRENT_IND"='Y')
21 - filter("ROW_CURRENT_IND"='Y')
22 - filter("ROW_CURRENT_IND"='Y' AND "CONROL_REGISTER"='X')
ENVIRONMENT B
Plan hash value: 2826260434
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1 | 181 | 103K (2)| 00:20:47 |
| 1 | HASH UNIQUE | | 1 | 181 | 103K (2)| 00:20:47 |
|* 2 | HASH JOIN ANTI | | 1 | 181 | 103K (2)| 00:20:47 |
|* 3 | HASH JOIN | | 1 | 176 | 56855 (2)| 00:11:23 |
|* 4 | HASH JOIN | | 1 | 163 | 36577 (2)| 00:07:19 |
|* 5 | TABLE ACCESS BY INDEX ROWID | ASSET | 1 | 44 | 4 (0)| 00:00:01 |
| 6 | NESTED LOOPS | | 1 | 131 | 9834 (2)| 00:01:59 |
| 7 | NESTED LOOPS | | 1 | 87 | 9830 (2)| 00:01:58 |
| 8 | NESTED LOOPS | | 1 | 74 | 9825 (2)| 00:01:58 |
|* 9 | HASH JOIN | | 1 | 52 | 9820 (2)| 00:01:58 |
|* 10 | TABLE ACCESS BY INDEX ROWID| METER_CONFIG_HEADER | 1 | 14 | 1 (0)| 00:00:01 |
| 11 | NESTED LOOPS | | 1 | 33 | 116 (2)| 00:00:02 |
|* 12 | TABLE ACCESS FULL | METER_CONFIG_ITEM | 1 | 19 | 115 (2)| 00:00:02 |
|* 13 | INDEX RANGE SCAN | SYS_C00116570 | 1 | | 1 (0)| 00:00:01 |
|* 14 | TABLE ACCESS FULL | SERVICE_DELIVERY_POINT | 723K| 13M| 9699 (2)| 00:01:57 |
|* 15 | TABLE ACCESS BY INDEX ROWID | NMI | 1 | 22 | 5 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | IDX_NMI_ID_NK | 2 | | 2 (0)| 00:00:01 |
|* 17 | TABLE ACCESS BY INDEX ROWID | SDP_LOGICAL_ASSET | 1 | 13 | 5 (0)| 00:00:01 |
|* 18 | INDEX RANGE SCAN | IDX_SLA_SDP_SK | 2 | | 2 (0)| 00:00:01 |
|* 19 | INDEX RANGE SCAN | IDX_A_SAPINTLOGDEV_SK | 2 | | 2 (0)| 00:00:01 |
|* 20 | TABLE ACCESS FULL | REGISTER | 76113 | 2378K| 26743 (2)| 00:05:21 |
|* 21 | TABLE ACCESS FULL | SDP_LOGICAL_REGISTER | 5095K| 63M| 20245 (2)| 00:04:03 |
| 22 | VIEW | | 90889 | 443K| 47021 (2)| 00:09:25 |
|* 23 | HASH JOIN | | 90889 | 2307K| 47021 (2)| 00:09:25 |
|* 24 | TABLE ACCESS FULL | REGISTER | 76113 | 966K| 26743 (2)| 00:05:21 |
|* 25 | TABLE ACCESS FULL | SDP_LOGICAL_REGISTER | 5095K| 63M| 20245 (2)| 00:04:03 |
Predicate Information (identified by operation id):
2 - access("SERVICE_DELIVERY_POINT_SK"="TMP"."SERVICE_DELIVERY_POINT_SK")
3 - access("SERVICE_DELIVERY_POINT_SK"="SERVICE_DELIVERY_POINT_SK" AND
"SAP_INT_LOGICAL_REGISTER_SK"="SAP_INT_LOGICAL_REGISTER_SK")
4 - access("ASSET_CD"="EQUIP_CD")
5 - filter("ROW_CURRENT_IND"='Y')
9 - access("NETWORK_TARIFF_CD"="NETWORK_TARIFF_CD")
10 - filter("ROW_CURRENT_IND"='Y')
12 - filter("ROW_CURRENT_IND"='Y' AND "CONROL_REGISTER"='X')
13 - access("METER_CONFIG_HEADER_SK"="METER_CONFIG_HEADER_SK")
14 - filter("ROW_CURRENT_IND"='Y')
15 - filter("ROW_CURRENT_IND"='Y' AND ("NMI_STATUS_CD"='A' OR "NMI_STATUS_CD"='D'))
16 - access("NMI_SK"="NMI_SK")
17 - filter("ROW_CURRENT_IND"='Y')
18 - access("SERVICE_DELIVERY_POINT_SK"="SERVICE_DELIVERY_POINT_SK")
19 - access("SAP_INT_LOG_DEVICE_SK"="SAP_INT_LOG_DEVICE_SK")
20 - filter((SUBSTR("REGISTER_ID_CD",1,1)='4' OR SUBSTR("REGISTER_ID_CD",1,1)='5' OR
SUBSTR("REGISTER_ID_CD",1,1)='6') AND "REGISTER_TYPE_CD"='C' AND "ROW_CURRENT_IND"='Y')
21 - filter("ROW_CURRENT_IND"='Y')
23 - access("SAP_INT_LOGICAL_REGISTER_SK"="SAP_INT_LOGICAL_REGISTER_SK")
24 - filter((SUBSTR("REGISTER_ID_CD",1,1)='1' OR SUBSTR("REGISTER_ID_CD",1,1)='2' OR
SUBSTR("REGISTER_ID_CD",1,1)='3') AND "REGISTER_TYPE_CD"='C' AND "ROW_CURRENT_IND"='Y')
25 - filter("ROW_CURRENT_IND"='Y')Edited by: abhilash173 on Feb 24, 2013 9:16 PM
Edited by: abhilash173 on Feb 24, 2013 9:18 PMHi Paul,
I misread your question initially .The system stats are outdated in both ( same result as seen from aux_stats) .I am not a DBA and do not have access to gather system stats fresh.
select * from sys.aux_stats$
SNAME PNAME PVAL1 PVAL2
SYSSTATS_INFO STATUS NULL COMPLETED
SYSSTATS_INFO DSTART NULL 02-16-2011 15:24
SYSSTATS_INFO DSTOP NULL 02-16-2011 15:24
SYSSTATS_INFO FLAGS 1 NULL
SYSSTATS_MAIN CPUSPEEDNW 1321.20523 NULL
SYSSTATS_MAIN IOSEEKTIM 10 NULL
SYSSTATS_MAIN IOTFRSPEED 4096 NULL
SYSSTATS_MAIN SREADTIM NULL NULL
SYSSTATS_MAIN MREADTIM NULL NULL
SYSSTATS_MAIN CPUSPEED NULL NULL
SYSSTATS_MAIN MBRC NULL NULL
SYSSTATS_MAIN MAXTHR NULL NULL
SYSSTATS_MAIN SLAVETHR NULL NULL -
CBO not picking the right execution plan
Database: Oracle 9.2.0.6 EE
OS:Solaris 9
I am trying to tune a query that is generated via Siebel Analytics. I am seeing a behaviour which is puzzling me but hopefully would be 'elementary' for someone like JPL.
The query is based on a total of 7 tables. If I comment out any 2 dimension tables, the query picks up the right index on the fact table. However, the moment I add another table to the query, the plan goes awry.
The query with 5 tables is as below:
select count(distinct decode( T30256.HEADER_FLG , 'N' , T30256.ROW_WID ) ) as c1,
T352305.DAY_DT as c2,
case when T44643.PRODUCT_CLASS_NAME = 'MobileSubscription' then T40081.ATTR15_CHAR_VAL else 'Unspecified' end as c3,
T352305.ROW_WID as c5
from
W_PRODUCT_D T30955,
W_PRDATTRNM_D T44643,
W_DAY_D T352305,
W_ORDERITEM_F T30256,
W_PRDATTR_D T40081
where ( T30955.ROW_WID = T44643.ROW_WID
and T30256.LAST_UPD_DT_WID = T352305.ROW_WID
and T30256.PROD_ATTRIB_WID = T40081.ROW_WID
and T30256.PROD_WID = T30955.ROW_WID
and T30955.PROD_NAME = 'Mobile Subscription'
and (case when T44643.PRODUCT_CLASS_NAME = 'MobileSubscription' then T40081.ATTR15_CHAR_VAL else 'Unspecified' end in ('BT150BB-18M', 'BT250BB-18M', 'BT50BB-18M', 'BT600BB-18M'))
and T352305.DAY_DT between TO_DATE('2008-09-27' , 'YYYY-MM-DD') - 7 and TO_DATE('2008-09-27' , 'YYYY-MM-DD') - 1
group by
T352305.ROW_WID, T352305.DAY_DT,
case when T44643.PRODUCT_CLASS_NAME = 'MobileSubscription' then T40081.ATTR15_CHAR_VAL else 'Unspecified' end
;And the execution plan is as below:
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
| 0 | SELECT STATEMENT | | 269 | 25824 | 18660 (3)|
| 1 | SORT GROUP BY | | 269 | 25824 | 18660 (3)|
| 2 | NESTED LOOPS | | 269 | 25824 | 18658 (3)|
| 3 | NESTED LOOPS | | 6826 | 579K| 4734 (3)|
| 4 | MERGE JOIN CARTESIAN | | 8 | 544 | 6 (17)|
| 5 | NESTED LOOPS | | 1 | 54 | 4 (25)|
| 6 | TABLE ACCESS BY INDEX ROWID| W_PRODUCT_D | 1 | 37 | 3 (34)|
|* 7 | INDEX RANGE SCAN | W_PRODUCT_D_M2 | 1 | | 2 (50)|
| 8 | TABLE ACCESS BY INDEX ROWID| W_PRDATTRNM_D | 1 | 17 | 2 (50)|
|* 9 | INDEX UNIQUE SCAN | W_PRDATTRNM_D_P1 | 1 | | |
| 10 | BUFFER SORT | | 8 | 112 | 4 (0)|
| 11 | TABLE ACCESS BY INDEX ROWID| W_DAY_D | 8 | 112 | 3 (34)|
|* 12 | INDEX RANGE SCAN | W_DAY_D_M39 | 8 | | 2 (50)|
| 13 | TABLE ACCESS BY INDEX ROWID | W_ORDERITEM_F | 849 | 16131 | 592 (3)|
|* 14 | INDEX RANGE SCAN | W_ORDERITEM_F_INDX9 | 852 | | 4 (25)|
|* 15 | INDEX RANGE SCAN | W_PRDATTR_D_M29_T1 | 1 | 9 | 3 (34)|
----------------------------------------------------------------------------------------------Note how the dimension tables W_PRODUCT_D & W_DAY_D are joined using cartesian join before joining to the fact table W_ORDERITEM_F using the composite index 'W_ORDERITEM_F_INDX9'. This index consists of LAST_UPD_DT_WID, PROD_WID and ACTION_TYPE_WID, which are foreign keys to the dimension tables.
Now if I add one more table to the query:
select count(distinct decode( T30256.HEADER_FLG , 'N' , T30256.ROW_WID ) ) as c1,
T352305.DAY_DT as c2,
case when T44643.PRODUCT_CLASS_NAME = 'MobileSubscription' then T40081.ATTR15_CHAR_VAL else 'Unspecified' end as c3,
T30371.X_BT_DLR_GROUP as c4,
T352305.ROW_WID as c5
from W_PRODUCT_D T30955,
W_PRDATTRNM_D T44643,
W_DAY_D T352305,
W_ORDERITEM_F T30256,
W_ORDER_D T30371,
W_PRDATTR_D T40081
where ( T30955.ROW_WID = T44643.ROW_WID
and T30256.LAST_UPD_DT_WID = T352305.ROW_WID
and T30256.PROD_ATTRIB_WID = T40081.ROW_WID
and T30256.PROD_WID = T30955.ROW_WID
and T30256.ORDER_WID = T30371.ROW_WID
and T30955.PROD_NAME = 'Mobile Subscription'
and T30371.STATUS_CD = 'Complete'
and T30371.ORDER_TYPE = 'Sales Order'
and (case when T44643.PRODUCT_CLASS_NAME = 'MobileSubscription' then T40081.ATTR15_CHAR_VAL else 'Unspecified' end in ('BT150BB-18M', 'BT250BB-18M', 'BT50BB-18M', 'BT600BB-18M'))
and T352305.DAY_DT between TO_DATE('2008-09-27' , 'YYYY-MM-DD') - 7 and TO_DATE('2008-09-27' , 'YYYY-MM-DD') - 1
group by T30371.X_BT_DLR_GROUP, T352305.ROW_WID, T352305.DAY_DT,
case when T44643.PRODUCT_CLASS_NAME = 'MobileSubscription' then T40081.ATTR15_CHAR_VAL else 'Unspecified' end;I have added a single table W_ORDER_D to the query, and the execution plan is:
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
| 0 | SELECT STATEMENT | | 44 | 6336 | 78695 (3)|
| 1 | SORT GROUP BY | | 44 | 6336 | 78695 (3)|
| 2 | NESTED LOOPS | | 44 | 6336 | 78694 (3)|
| 3 | NESTED LOOPS | | 269 | 27707 | 78145 (3)|
|* 4 | HASH JOIN | | 6826 | 626K| 64221 (3)|
| 5 | TABLE ACCESS BY INDEX ROWID | W_DAY_D | 8 | 112 | 4 (25)|
|* 6 | INDEX RANGE SCAN | W_DAY_D_M39 | 1 | | 3 (34)|
| 7 | TABLE ACCESS BY INDEX ROWID | W_ORDERITEM_F | 86886 | 2206K| 64197 (3)|
| 8 | NESTED LOOPS | | 87004 | 6797K| 64200 (3)|
| 9 | NESTED LOOPS | | 1 | 54 | 4 (25)|
| 10 | TABLE ACCESS BY INDEX ROWID| W_PRODUCT_D | 1 | 37 | 3 (34)|
|* 11 | INDEX RANGE SCAN | W_PRODUCT_D_M2 | 1 | | 2 (50)|
| 12 | TABLE ACCESS BY INDEX ROWID| W_PRDATTRNM_D | 1 | 17 | 2 (50)|
|* 13 | INDEX UNIQUE SCAN | W_PRDATTRNM_D_P1 | 1 | | |
|* 14 | INDEX RANGE SCAN | W_ORDERITEM_F_N6 | 86886 | | 212 (18)|
|* 15 | INDEX RANGE SCAN | W_PRDATTR_D_M29_T1 | 1 | 9 | 3 (34)|
|* 16 | INDEX RANGE SCAN | W_ORDER_D_N6 | 1 | 41 | 3 (34)|
-----------------------------------------------------------------------------------------------Now CBO doesn't choose the composite index and the cost also has increased to 78695. But if I simply add an /*+ORDERED*/ hint to the above query, so that it should join the dimension tables before joining to fact table, then the cost drops to 20913. This means that CBO is not choosing the plan with the lowest cost. I tried increasing the optimizer_max_permutations to 80000, setting session level optimizer_dynamic_sampling to 8 (just to see if it works), but no success.
Could you please advise how to overcome this problem?
Many thanks.joshic wrote:
Database: Oracle 9.2.0.6 EE
OS:Solaris 9
I am trying to tune a query that is generated via Siebel Analytics. I am seeing a behaviour which is puzzling me but hopefully would be 'elementary' for someone like JPL.
The query is based on a total of 7 tables. If I comment out any 2 dimension tables, the query picks up the right index on the fact table. However, the moment I add another table to the query, the plan goes awry.
I have added a single table W_ORDER_D to the query, and the execution plan is:
Now CBO doesn't choose the composite index and the cost also has increased to 78695. But if I simply add an /*+ORDERED*/ hint to the above query, so that it should join the dimension tables before joining to fact table, then the cost drops to 20913. This means that CBO is not choosing the plan with the lowest cost. I tried increasing the optimizer_max_permutations to 80000, setting session level optimizer_dynamic_sampling to 8 (just to see if it works), but no success.Back to the original question:
* Can you force the index usage of the composite index on W_ORDERITEM_F in the second query using an INDEX hint (instead of the ORDERED hint)? If yes, what does the plan look like, particularly what cost is reported?
* Could you post the plans including the "Predicate Information" section below the plan output?
* What is the definition of the index W_ORDERITEM_F_N6 on W_ORDERITEM_F?
* Are the cardinalities reported in the execution plans close to reality or way off? The best way to verify this would be to run your query with SQL tracing enabled and generate a tkprof output. If you do so please post the tkprof output here as well.
Regards,
Randolf
Oracle related stuff blog:
http://oracle-randolf.blogspot.com/
SQLTools++ for Oracle (Open source Oracle GUI for Windows):
http://www.sqltools-plusplus.org:7676/
http://sourceforge.net/projects/sqlt-pp/ -
Understanding CBO decisions, explain plan instability
Hi,
I have a situation where the explain plan for a SELECT statement changes
and performance takes a turn for the worse. The statement in question
executes well and has the desired explain plan but after an insertion
having a new eventtype ID the explain plan changes (doing lots of IO)
and remains bad until the SGA is flushed.
I would really like to know how to figure out how the CBO makes its
decisions and why it changes its mind over a 2min period. Any pointers
to get me started would be greatly appreciated.
Table has columns C_ID, R_ID, EVENTTYPE, ...
Regular indexes on (R_ID,C_ID) and EVENTTYPE.
The SELECT runs well as long as the compound index is used first
and runs poorly once a new EVENTTYPE is introduced (there are
approx 10 event types and a new one is being introduced) and its
index consulted first.
Thansk,
DarrenDelayed block cleanout really confused me. I don't see how
the details of block updates, SCNs and what is on disk relates
to explain plans and a SQL statement that changes from
performing well using the intended index to poorly using an index
on a column having low cardinality.
The SQL is actually quite trivial and a merely a lookup on this
single table.
SELECT * FROM table
WHERE c_id = :1 and r_id = :2 and eventtype = :3
Most of the time Oracle uses the intended index (r_id, c_id) and
performs well. As long as both columns are used in the condition
I don't think that ordering of them is an issue.
If the CBO uses stats which get updated nightly after sufficient
changes to the table then how can a statement change its execution
plans (for the same user) following a addition of a row having a
new EVENTTYPE value over a 2min period.
That is the reason that I want to see/understand what the CBO
is doing.
It turns out that adding a new index (C_ID, R_ID, EVENTTYPE) was
the bandaid needed to fix the problem but I'd like to get rid of
it if its not needed.
I'll look at these posts and try to get the differing plans back.
At this point I'll need to drop the new index and break the app
again and might receive some resistance to that.
Thanks for your input,
Darren -
Is there a way to stop a query just after the cursor/plan is produced by CBO?
Following suggestions of Kerry Osborne’s Oracle Blog » Blog Archive » Explain Plan Lies – Kerry Osborn…
on the lies of "Explain plan" (and of "set autotrace on" too) I'd like to try to stop a query/DML before actually it starts, just after the plan was produced and sql_id assigned.
Is there any CLEAN way (other than trying CTRL-C) to do that?
Thanks
PaoloHi
PaolFili wrote:
Thanks rp.
I think my question is a little dofferent, but your reply give me an idea.(which has clear disadvantages , but can do the work).
The problem is obtain in Lybrary Cache a plan,a SLQ_ID,PLAN_HASH for a query ( i.e. a 10days running query) that I cannot start-up.
So my (suggested from your reply) idea is:
1) to LOCK EXCLUSIVE (a table level) , **if it's possible** every table accessed in the query ( Yes, it can be really expansive in some production environment, but sometimes can be necessary ..)
using : LOCK TABLE table IN EXCLUSIVE MODE
for each table accessed from query
2) Startup the query that will be suspended form the lock on tables accessed + kill the sid,serial#,@Inst_id for the query.
3) UNLOCK tables from EXCLUSIVE using "ROLLBACK" in the session where LOCK TABLE.... was send.(to remake tables to work for other queries)
Any other ideas?
Thanks
Paolo
you're planning on using locks to stop a query and you think in order to do so you need exclusive locks on every table accessed in the query? And you are prepared to do that on a production system?
And all of this is needed to troubleshoot a query that was running for 10 days -- i.e. a query that was available for all kinds of diagnostics during 10 days?
Sorry, I think it wasn't a good idea for you to read that Osborne's blog post -- you should've started with more basic things. Way more basic.
Best regards,
Nikolay -
Two different plans in TEST & Prod
hi,
we have a problem in production database where we find some sql statements running very slow.
but if you run same SQL statement in TEST it runs < 2 secs.
Production DB Prod.SchemaA is exported into TEST DB as Test.SchemaA
When study the explain plan, we find Prod explain plan is different than test. if you create sql profile, by copying TEST explain plan, it would run faster in Production.
Now our question is why optimizer goes through two different plans when the schema structure same and data almost same in two databases?
Note that, we have two almost identical schema's in Production. Prod.SchemaA and Prod.SchemaB has same object names but some Prod.SchemaB may have small difference in indexes/constraints.
Users would run same SQL statement both in Prod.SchemaA & Prod.SchemaB time to time.
thanks
nealYou can have a clear picture about the accuracy of your statistics by getting the execution plan from memory into the TEST and PROD environment. You can proceed as follows
PROD> alter session set statistics_level=ALL;
PROD> execute your query;
PROD> select * from table (dbms_xplan.display_cursor(null,null, 'ALLSTATS LAST'));
TEST> alter session set statistics_level=ALL;
TEST> execute your query
TEST> select * from table (dbms_xplan.display_cursor(null,null, 'ALLSTATS LAST'));
This will give an execution plan showing the estimations(E-Rows) done by the CBO and the Actual (A-Rows) rows generated allowing you to judge the accuracy of your statistics.
The predicate part of the execution plan can also show inportant information.
Best regards
Mohamed Houri
www.hourim.wordpress.com -
Execution plan with bind variable
dear all
I join two tables and get "index fast full scan" with high cost using bind variable
but when I remove the bind variable it executes with "index" and with lower cost
What is the reason and how should I know which execution plan is really used in real life?
thanks
john1) What is oracle version?
2) Post here both query and their explain plan.
In fact INDEX FAST FULL SCAN indicate is multiblock read for composite indexes(and based on your query and predicates).In this case CBO behavior as FULL TABLE SCAN(affected by db_multiblock_read_count,system stats,etc).And you use bind variable.So in bind variable case CBO define selectivity based on arithmetic(5% of the cardinality) ,if you use concrete values instead of bind variable CBO identify other selectivity based on statistics,histograms,.... then it was identify cost of multiblock read and single block reads.You can see these 10053 event.Finally it choose lower cost`s plan. -
Any known CBO issues in 9.2.0.8?
Hi, we have a job that runs considerably slower on 9.2.0.8 than it does on 9.2.0.5 and 10G R2. For many SQL statements it chooses a different execution plan than in the other versions and almost always a much slower one.
Are there any known issues with the CBO in 9.2.0.8.?
ReneKnown does not mean known to Oracle at the time of release. It is a reference to the knowledge contained in the minds of people reading this forum. I'm asking for similar experiences with the 9.2.0.8 CBO (in that it acts different from the 9.2.0.5 CBO) and what to do with it.
Rene -
CBO bug? Lack of SORT UNIQUE.
Hi all,
Let's consider following case:
create table tmp as select rownum id, 0 sign from dual connect by level <= 100;
create index tmp_i on tmp(id,sign);
create table t as
select mod(rownum,2) id, mod(rownum,3) val
from dual
connect by level <= 100000;
begin
dbms_stats.gather_table_stats (
user,
'T',
estimate_percent => null,
method_opt => 'FOR ALL COLUMNS SIZE SKEWONLY',
cascade => true
end;
begin
dbms_stats.gather_table_stats (
user,
'TMP',
estimate_percent => null,
method_opt => 'FOR ALL COLUMNS SIZE SKEWONLY',
cascade => true
end;
/As you can see it scans TMP_I 50 000 times for statement with max (irrespective of distinct in subquery).
Is there any way to enforce CBO to make SORT UNIQUE for max as well as for count so that it scans TMP_I only 3 times?
SQL> select --+ leading(t) use_nl(t tmp)
2 max(id)
3 from tmp tmp
4 where tmp.sign = 0
5 and tmp.id in (select val from t where id = 1);
MAX(ID)
2
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.14 | 159 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.14 | 159 |
| 2 | NESTED LOOPS | | 1 | 49750 | 33333 |00:00:00.13 | 159 |
|* 3 | TABLE ACCESS FULL| T | 1 | 50000 | 50000 |00:00:00.02 | 156 |
|* 4 | INDEX RANGE SCAN | TMP_I | 50000 | 1 | 33333 |00:00:00.07 | 3 |
Predicate Information (identified by operation id):
3 - filter("ID"=1)
4 - access("TMP"."ID"="VAL" AND "TMP"."SIGN"=0)
SQL> select --+ leading(t) use_nl(t tmp)
2 max(id)
3 from tmp tmp
4 where tmp.sign = 0
5 and tmp.id in (select distinct val from t where id = 1);
MAX(ID)
2
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.14 | 159 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.14 | 159 |
| 2 | NESTED LOOPS | | 1 | 49750 | 33333 |00:00:00.13 | 159 |
|* 3 | TABLE ACCESS FULL| T | 1 | 50000 | 50000 |00:00:00.01 | 156 |
|* 4 | INDEX RANGE SCAN | TMP_I | 50000 | 1 | 33333 |00:00:00.07 | 3 |
Predicate Information (identified by operation id):
3 - filter("ID"=1)
4 - access("TMP"."ID"="VAL" AND "TMP"."SIGN"=0)
SQL> select --+ leading(t) use_nl(t tmp)
2 count(id)
3 from tmp tmp
4 where tmp.sign = 0
5 and tmp.id in (select val from t where id = 1);
COUNT(ID)
2
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.03 | 158 | | | |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.03 | 158 | | | |
| 2 | NESTED LOOPS | | 1 | 3 | 2 |00:00:00.03 | 158 | | | |
| 3 | SORT UNIQUE | | 1 | 50000 | 3 |00:00:00.03 | 156 | 2048 | 2048 | 2048 (0)|
|* 4 | TABLE ACCESS FULL| T | 1 | 50000 | 50000 |00:00:00.01 | 156 | | | |
|* 5 | INDEX RANGE SCAN | TMP_I | 3 | 1 | 2 |00:00:00.01 | 2 | | | |
Predicate Information (identified by operation id):
4 - filter("ID"=1)
5 - access("TMP"."ID"="VAL" AND "TMP"."SIGN"=0)I can't figure out why SORT UNIQUE is absent for statement with max.
PS. 11gR2Thanks for reply.
user503699 wrote:
I don't think it is a good idea to compare your last and first query timings as they are 2 different queries.Ok. I could compare query with max(id), sign(count(*)+1) vs max(id), sign(1). They always produce the same results so can be considered as the same.
But I think that max(id), count(*) vs max(id) was enough to explain my point.
user503699 wrote:
If you are so sure of that you can write something like following :
SQL> with data as (select /*+ materialize */ distinct val as val from t where id = 1)
select max(id) from tmp tmp where tmp.sign = 0 and tmp.id in (select val from data) ; 2
I thought about that. I’m reluctant to use undocumented hints such as materialize. So folowing query has almost the best plan for my data:
with data as (select distinct val as val from t where id = 1 and rownum > 0)
select
max(id)
from tmp tmp
where tmp.sign = 0
and tmp.id in (select * from data);
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1 | 8 | 50 (8)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
| 2 | NESTED LOOPS | | 3 | 24 | 50 (8)| 00:00:01 |
| 3 | VIEW | | 3 | 9 | 50 (8)| 00:00:01 |
| 4 | HASH UNIQUE | | 3 | 18 | 50 (8)| 00:00:01 |
| 5 | COUNT | | | | | |
|* 6 | FILTER | | | | | |
|* 7 | TABLE ACCESS FULL| T | 50000 | 292K| 47 (3)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | TMP_I | 1 | 5 | 0 (0)| 00:00:01 |
Predicate Information (identified by operation id):
6 - filter(ROWNUM>0)
7 - filter("ID"=1)
8 - access("TMP"."ID"="DATA"."VAL" AND "TMP"."SIGN"=0) And changing two hidden parameters may lead to the same plan as I expect:
alter session set "_gby_hash_aggregation_enabled" = false;
alter session set "_simple_view_merging" = false;
with data as (select distinct val as val from t where id = 1)
select
max(id)
from tmp tmp
where tmp.sign = 0
and tmp.id in (select * from data);
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1 | 18 | 50 (8)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 18 | | |
| 2 | NESTED LOOPS | | 3 | 54 | 50 (8)| 00:00:01 |
| 3 | VIEW | | 3 | 39 | 50 (8)| 00:00:01 |
| 4 | SORT UNIQUE | | 3 | 18 | 50 (8)| 00:00:01 |
|* 5 | TABLE ACCESS FULL| T | 50000 | 292K| 47 (3)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | TMP_I | 1 | 5 | 0 (0)| 00:00:01 |
Predicate Information (identified by operation id):
5 - filter("ID"=1)
6 - access("TMP"."ID"="DATA"."VAL" AND "TMP"."SIGN"=0) But here I've got two additional questions:
1. no_use_hash_aggregation can be used instead of "alter session set "_gby_hash_aggregation_enabled" = false;"
What hint can be used instead of "alter session set "_simple_view_merging" = false;"?
2. Is there any way to enforce CBO to use for this one
select
max(id)
from tmp tmp
where tmp.sign = 0
and tmp.id in (select distinct val as val from t where id = 1 and rownum > 0);
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1 | 5 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 5 | | |
| 2 | FIRST ROW | | 1 | 5 | 1 (0)| 00:00:01 |
|* 3 | INDEX FULL SCAN (MIN/MAX)| TMP_I | 1 | 5 | 1 (0)| 00:00:01 |
|* 4 | FILTER | | | | | |
| 5 | COUNT | | | | | |
|* 6 | FILTER | | | | | |
|* 7 | TABLE ACCESS FULL | T | 2 | 12 | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------- the same plan as for this
with data as (select distinct val as val from t where id = 1 and rownum > 0)
select
max(id)
from tmp tmp
where tmp.sign = 0
and tmp.id in (select * from data);
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1 | 8 | 50 (8)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
| 2 | NESTED LOOPS | | 3 | 24 | 50 (8)| 00:00:01 |
| 3 | VIEW | | 3 | 9 | 50 (8)| 00:00:01 |
| 4 | HASH UNIQUE | | 3 | 18 | 50 (8)| 00:00:01 |
| 5 | COUNT | | | | | |
|* 6 | FILTER | | | | | |
|* 7 | TABLE ACCESS FULL| T | 50000 | 292K| 47 (3)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | TMP_I | 1 | 5 | 0 (0)| 00:00:01 |
I don't have anything against subquery factoring clause. Just for personal interest.
(I have read topic "Thread: Materialize a Subquery without using "with" clause"
Materialize a Subquery without using "with" clause
user503699 wrote:
If you are not going to change other things (like stats collection method, table/index structures etc.) which allow optimizer to choose better plan and you know your data better, you may need to be very specific with the hints and also may have to use additional hints in order to influence optimizer decisions.
One way to do that would be to get the base details from oracle as follows (and tweak them) :I didn't find keyword "ADVANCED" in specification for DISPLAY_CURSOR Function in documentation. Nice trick.
But anyway outline data makes sense only in case when query already has desirable execution plan. -
Subquery conditional execution using cbo
hellou
how i do for execute a subquery conditionally, using the cbo??
i got an example:
create table table1 AS
SELECT * FROM (
SELECT 1 id, 'a' boss FROM dual
union all
SELECT 3 id, 'b' boss FROM dual
union all
SELECT 5 id, 'a' boss FROM dual
union all
SELECT 7 id, 'b' boss FROM dual
union all
SELECT 9 id, 'a' boss FROM dual
create index idx_table1 on table1(boss, id)
create table table2 AS
SELECT * FROM (
SELECT 2 id, 'b' boss FROM dual
union all
SELECT 4 id, 'a' boss FROM dual
union all
SELECT 6 id, 'b' boss FROM dual
union all
SELECT 8 id, 'a' boss FROM dual
union all
SELECT 10 id, 'b' boss FROM dual
create index idx_table2 on table2(boss, id)
CREATE OR REPLACE FUNCTION print_hi
isb in varchar2
return number
IS
BEGIN
dbms_output.put_Line(isb);
return 0;
END;
-- the query !!!!!!!
with data AS
SELECT
FROM (
-- subquery #1
SELECT
1 query_name,
id pibot,
boss
FROM table1
WHERE print_hi(id) = 0
union all
-- subquery #2
SELECT
2 query_name,
id pibot,
boss
FROM table2
SELECT
pibot + query_name / 10 pibot
FROM data
WHERE 1 = 1
AND boss = :boss
AND (
query_name = :q
AND pibot > :p
OR query_name > :q )
AND rownum <= 3i want than only the query #2 be executed.
the query #1 print data in the screen when is executed (for the function print_hi).
now i execute the query with the variables data as:
boss = 'a'
q = 2
p = 0
when i execute the query using rules, then not print anything in the screen.
when i execute the query using costs, then print 1 5 9 in the screen. this means than the query #1 is being executed when this should not
help .. tx
SELECT * FROM v$version
Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - Prod
PL/SQL Release 10.2.0.5.0 - Production
CORE10.2.0.5.0Production
TNS for Linux: Version 10.2.0.5.0 - Production
NLSRTL Version 10.2.0.5.0 - ProductionAs often is, the predicates section of the execution plan is quite revealing on this one.
Take your original query
explain plan for
with data AS
(SELECT *
FROM (-- subquery #1
SELECT 1 query_name,id pibot,boss
FROM table1
WHERE print_hi(id) = 0
union all
-- subquery #2
SELECT 2 query_name,id pibot,boss
FROM table2))
SELECT pibot + query_name / 10 pibot
FROM data
WHERE 1 = 1
AND boss = :boss
AND (query_name = :q
AND pibot > :p
OR query_name > :q )
AND rownum <= 3;
select * from table(dbms_xplan.display);gives
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 2 | 38 | 2 (0)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | VIEW | | 2 | 38 | 2 (0)| 00:00:01 |
| 3 | UNION-ALL | | | | | |
|* 4 | INDEX RANGE SCAN| IDX_TABLE1 | 1 | 16 | 1 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN| IDX_TABLE2 | 1 | 16 | 1 (0)| 00:00:01 |
Predicate Information (identified by operation id):
1 - filter(ROWNUM<=3)
4 - access("BOSS"=:BOSS)
filter("PRINT_HI"(TO_CHAR("ID"))=0 AND (1>TO_NUMBER(:Q) OR
1=TO_NUMBER(:Q) AND "ID">TO_NUMBER(:P)))
5 - access("BOSS"=:BOSS)
filter(2>TO_NUMBER(:Q) OR 2=TO_NUMBER(:Q) AND "ID">TO_NUMBER(:P))Assuming that the FILTER logic in STEP 4 is followed to order, it's not then possible with this query as is to short-circuit the evaluation of PRINT_HI as it is evaluated first.
When you make a change (just to q not necessarily to boss as well)
from
query_name = :qto
query_name = 2You'll hopefully notice the difference in predicate evaluation with the extra filter step:
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 2 | 38 | 2 (0)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | VIEW | | 2 | 38 | 2 (0)| 00:00:01 |
| 3 | VIEW | | 2 | 38 | 2 (0)| 00:00:01 |
| 4 | UNION-ALL | | | | | |
|* 5 | FILTER | | | | | |
|* 6 | INDEX RANGE SCAN| IDX_TABLE1 | 1 | 16 | 1 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | IDX_TABLE2 | 1 | 16 | 1 (0)| 00:00:01 |
Predicate Information (identified by operation id):
1 - filter(ROWNUM<=3)
5 - filter(1>TO_NUMBER(:Q))
6 - access("BOSS"=:BOSS)
filter("PRINT_HI"(TO_CHAR("ID"))=0)
7 - access("BOSS"=:BOSS)
filter("ID">TO_NUMBER(:P) OR 2>TO_NUMBER(:Q)) -
Hi,
I am quite new to use explain plan in oracle.
I want to know what are the important factors that we should emphasize to optimize a SQL query.
Thanks in Advance,
DilipIf I had to identify key SQL tuning factors to look for in relation to an explain plan I would say that number one is to verify that the plan is driving on the right tables in the proper order.
Second looking at the SQL make sure it is not written in such a manner as to disable the use of available indexes such as when a trunc is done on an indexed date column so it can be compared equal to another date when a >= date value of midnight and < midnight of first day not desired could be used instead enabling use of the index on the date column by the optimizer. Implicit conversions of join column data types can also disable use of an index.
Third, if the CBO is doing something other than what you expected do not just assume it is wrong. Try to figure out why it is doing what it is doing and then try to determine if it is right or wrong. I have caught people trying to tune SQL because they knew the plan was wrong, but did not actually test it before spending a lot of time to develop a different path that ran slower than the optimzer plan.
HTH -- Mark D Powell -- -
Hello,
Some days back, I came across a blog entry in which author concluded that when a = b and b = c, oracle does not conclude as a = c. He also provided a test case to prove his point. The URL is [http://sandeepredkar.blogspot.com/2009/09/query-performance-join-conditions.html]
Now, I thought that that can not be true. So I executed his test case (on 10.2.04) and the outcome indeed proved his point. Initially, I thought it might be due to absense of PK-FK relationship. But even after adding the PK-FK relationship, there was no change in the outcome. Although, when I modified the subquery with list of values, both the queries performed equally. I tried asking the author on his blog but it seems he has not yet seen my comment.
I am pasting his test case below. Can somebody please help me understand why CBO does not/can not use optimal plan here?
SQL> create table cu_all (custid number, addr varchar2(200), ph number, cano number, acctype varchar2(10));
Table created.
SQL> create table ca_receipt (custid number, caamt number, cadt date, totbal number);
Table created.
SQL>
SQL> insert into cu_all
2 select lvl,
3 dbms_random.string('A',30),
4 round(dbms_random.value(1,100000)),
5 round(dbms_random.value(1,10000)),
6 dbms_random.string('A',10)
7 from (select level "LVL" from dual connect by level <=200000);
200000 rows created.
SQL> insert into ca_receipt
2 select round(dbms_random.value(1,10000)),
3 round(dbms_random.value(1,100000)),
4 sysdate - round(dbms_random.value(1,100000)),
5 round(dbms_random.value(1,100000))
6 from (select level "LVL" from dual connect by level <=500000);
500000 rows created.
SQL> create unique index pk_cu_all_ind on cu_all(custid);
Index created.
SQL> create index ind2_cu_all on cu_all(CANO);
Index created.
SQL> create index ind_ca_receipt_custid on ca_receipt(custid);
Index created.
SQL> exec dbms_stats.gather_table_stats(user,'CU_ALL', cascade=>true);
PL/SQL procedure successfully completed.
SQL> exec dbms_stats.gather_table_stats(user,'CA_RECEIPT', cascade=>true);
PL/SQL procedure successfully completed.
Now let us execute the query with trace on. This is the similar query which was provided to me.
SQL> set autot trace
SQL> SELECT ca.*, cu.*
2 FROM ca_receipt CA,
3 cu_all CU
4 WHERE CA.CUSTID = CU.CUSTID
5 AND CA.CUSTID IN (SELECT CUSTID FROM cu_all START WITH custid = 2353
6 CONNECT BY PRIOR CUSTID = CANO)
7 ORDER BY ACCTYPE DESC;
289 rows selected.
Execution Plan
Plan hash value: 3186098611
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1000 | 81000 | 504 (2)| 00:00:07 |
| 1 | SORT ORDER BY | | 1000 | 81000 | 504 (2)| 00:00:07 |
|* 2 | HASH JOIN | | 1000 | 81000 | 503 (2)| 00:00:07 |
| 3 | NESTED LOOPS | | | | | |
| 4 | NESTED LOOPS | | 1000 | 26000 | 112 (1)| 00:00:02 |
| 5 | VIEW | VW_NSO_1 | 20 | 100 | 21 (0)| 00:00:01 |
| 6 | HASH UNIQUE | | 20 | 180 | | |
|* 7 | CONNECT BY WITH FILTERING | | | | | |
| 8 | TABLE ACCESS BY INDEX ROWID | CU_ALL | 1 | 9 | 2 (0)| 00:00:01 |
|* 9 | INDEX UNIQUE SCAN | PK_CU_ALL_IND | 1 | | 1 (0)| 00:00:01 |
| 10 | NESTED LOOPS | | | | | |
| 11 | CONNECT BY PUMP | | | | | |
| 12 | TABLE ACCESS BY INDEX ROWID| CU_ALL | 20 | 180 | 21 (0)| 00:00:01 |
|* 13 | INDEX RANGE SCAN | IND2_CU_ALL | 20 | | 1 (0)| 00:00:01 |
|* 14 | INDEX RANGE SCAN | IND_CA_RECEIPT_CUSTID | 50 | | 2 (0)| 00:00:01 |
| 15 | TABLE ACCESS BY INDEX ROWID | CA_RECEIPT | 50 | 1050 | 52 (0)| 00:00:01 |
| 16 | TABLE ACCESS FULL | CU_ALL | 200K| 10M| 389 (1)| 00:00:05 |
Predicate Information (identified by operation id):
2 - access("CA"."CUSTID"="CU"."CUSTID")
7 - access("CANO"=PRIOR "CUSTID")
9 - access("CUSTID"=2353)
13 - access("CANO"=PRIOR "CUSTID")
14 - access("CA"."CUSTID"="CUSTID")
Statistics
1 recursive calls
0 db block gets
2249 consistent gets
25 physical reads
0 redo size
11748 bytes sent via SQL*Net to client
729 bytes received via SQL*Net from client
21 SQL*Net roundtrips to/from client
7 sorts (memory)
0 sorts (disk)
289 rows processed
If you look at the query, it seems to be normal one.
But the problem is here-
Query is having two tables CA and CU. From the inner CU table query, it fetches records and joins with CA table an CA table Joins with CU table using the same column.
Here the inner query joins with CA table and cardinality of the query gets changed. So it is opting FTS when joining to CU table again.
This is causing the performance bottleneck. So to resolve the issue, I have change the joining condition.
Now if we check, following is the proper execution plan. Also the consistents gets have been reduced to 797 against 2249 in original query.
SQL> SELECT ca.*, cu.*
2 FROM ca_receipt CA,
3 cu_all CU
4 WHERE CA.CUSTID = CU.CUSTID
5 AND CU.CUSTID IN (SELECT CUSTID FROM cu_all START WITH custid = 2353
6 CONNECT BY PRIOR CUSTID = CANO)
7 ORDER BY ACCTYPE DESC;
289 rows selected.
Execution Plan
Plan hash value: 3713271440
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1000 | 81000 | 133 (2)| 00:00:02 |
| 1 | SORT ORDER BY | | 1000 | 81000 | 133 (2)| 00:00:02 |
| 2 | NESTED LOOPS | | | | | |
| 3 | NESTED LOOPS | | 1000 | 81000 | 132 (1)| 00:00:02 |
| 4 | NESTED LOOPS | | 20 | 1200 | 42 (3)| 00:00:01 |
| 5 | VIEW | VW_NSO_1 | 20 | 100 | 21 (0)| 00:00:01 |
| 6 | HASH UNIQUE | | 20 | 180 | | |
|* 7 | CONNECT BY WITH FILTERING | | | | | |
| 8 | TABLE ACCESS BY INDEX ROWID | CU_ALL | 1 | 9 | 2 (0)| 00:00:01 |
|* 9 | INDEX UNIQUE SCAN | PK_CU_ALL_IND | 1 | | 1 (0)| 00:00:01 |
| 10 | NESTED LOOPS | | | | | |
| 11 | CONNECT BY PUMP | | | | | |
| 12 | TABLE ACCESS BY INDEX ROWID| CU_ALL | 20 | 180 | 21 (0)| 00:00:01 |
|* 13 | INDEX RANGE SCAN | IND2_CU_ALL | 20 | | 1 (0)| 00:00:01 |
| 14 | TABLE ACCESS BY INDEX ROWID | CU_ALL | 1 | 55 | 1 (0)| 00:00:01 |
|* 15 | INDEX UNIQUE SCAN | PK_CU_ALL_IND | 1 | | 0 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | IND_CA_RECEIPT_CUSTID | 50 | | 2 (0)| 00:00:01 |
| 17 | TABLE ACCESS BY INDEX ROWID | CA_RECEIPT | 50 | 1050 | 52 (0)| 00:00:01 |
Predicate Information (identified by operation id):
7 - access("CANO"=PRIOR "CUSTID")
9 - access("CUSTID"=2353)
13 - access("CANO"=PRIOR "CUSTID")
15 - access("CU"."CUSTID"="CUSTID")
16 - access("CA"."CUSTID"="CU"."CUSTID")
Statistics
1 recursive calls
0 db block gets
797 consistent gets
1 physical reads
0 redo size
11748 bytes sent via SQL*Net to client
729 bytes received via SQL*Net from client
21 SQL*Net roundtrips to/from client
7 sorts (memory)
0 sorts (disk)
289 rows processeduser503699 wrote:
Hello,
Some days back, I came across a blog entry in which author concluded that when a = b and b = c, oracle does not conclude as a = c. He also provided a test case to prove his point. The URL is [http://sandeepredkar.blogspot.com/2009/09/query-performance-join-conditions.html]
Now, I thought that that can not be true. So I executed his test case (on 10.2.04) and the outcome indeed proved his point. Initially, I thought it might be due to absense of PK-FK relationship. But even after adding the PK-FK relationship, there was no change in the outcome. Although, when I modified the subquery with list of values, both the queries performed equally. I tried asking the author on his blog but it seems he has not yet seen my comment.I see that Jonathan provided a helpful reply to you while I was in the process of setting up a test case.
Is it possible that the optimizer is correct? What if... the optimizer transformed the SQL statement? What if... the original SQL statement actually executes faster than the modified SQL statement? What if... the autotrace plans do not match the plans shown on that web page?
The first execution with the original SQL statement:
ALTER SESSION SET EVENTS '10053 trace name context forever, level 1';
ALTER SESSION SET TRACEFILE_IDENTIFIER = 'test_case';
SET AUTOTRACE TRACE
SELECT ca.*, cu.*
FROM ca_receipt CA,
cu_all CU
WHERE CA.CUSTID = CU.CUSTID
AND CA.CUSTID IN (SELECT CUSTID FROM cu_all START WITH custid = 2353
CONNECT BY PRIOR CUSTID = CANO)
ORDER BY ACCTYPE DESC;
Execution Plan
Plan hash value: 2794552689
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1001 | 81081 | 1125 (2)| 00:00:01 |
| 1 | SORT ORDER BY | | 1001 | 81081 | 1125 (2)| 00:00:01 |
| 2 | NESTED LOOPS | | 1001 | 81081 | 1123 (1)| 00:00:01 |
| 3 | NESTED LOOPS | | 1001 | 26026 | 114 (2)| 00:00:01 |
| 4 | VIEW | VW_NSO_1 | 20 | 100 | 22 (0)| 00:00:01 |
| 5 | HASH UNIQUE | | 20 | 180 | | |
|* 6 | CONNECT BY WITH FILTERING | | | | | |
| 7 | TABLE ACCESS BY INDEX ROWID | CU_ALL | 1 | 19 | 2 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | PK_CU_ALL_IND | 1 | | 1 (0)| 00:00:01 |
| 9 | NESTED LOOPS | | | | | |
| 10 | CONNECT BY PUMP | | | | | |
| 11 | TABLE ACCESS BY INDEX ROWID| CU_ALL | 20 | 180 | 22 (0)| 00:00:01 |
|* 12 | INDEX RANGE SCAN | IND2_CU_ALL | 20 | | 1 (0)| 00:00:01 |
| 13 | TABLE ACCESS BY INDEX ROWID | CA_RECEIPT | 50 | 1050 | 52 (0)| 00:00:01 |
|* 14 | INDEX RANGE SCAN | IND_CA_RECEIPT_CUSTID | 50 | | 2 (0)| 00:00:01 |
| 15 | TABLE ACCESS BY INDEX ROWID | CU_ALL | 1 | 55 | 1 (0)| 00:00:01 |
|* 16 | INDEX UNIQUE SCAN | PK_CU_ALL_IND | 1 | | 0 (0)| 00:00:01 |
Predicate Information (identified by operation id):
6 - access("CANO"=PRIOR "CUSTID")
8 - access("CUSTID"=2353)
12 - access("CANO"=PRIOR "CUSTID")
14 - access("CA"."CUSTID"="$nso_col_1")
16 - access("CA"."CUSTID"="CU"."CUSTID")
Statistics
1 recursive calls
0 db block gets
232 consistent gets
7 physical reads
0 redo size
2302 bytes sent via SQL*Net to client
379 bytes received via SQL*Net from client
5 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
52 rows processedThe second SQL statement which was modified:
ALTER SESSION SET TRACEFILE_IDENTIFIER = 'test_case2';
SELECT ca.*, cu.*
FROM ca_receipt CA,
cu_all CU
WHERE CA.CUSTID = CU.CUSTID
AND CU.CUSTID IN (SELECT CUSTID FROM cu_all START WITH custid = 2353
CONNECT BY PRIOR CUSTID = CANO)
ORDER BY ACCTYPE DESC;
Execution Plan
Plan hash value: 497148844
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1001 | 81081 | 136 (3)| 00:00:01 |
| 1 | SORT ORDER BY | | 1001 | 81081 | 136 (3)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID | CA_RECEIPT | 50 | 1050 | 52 (0)| 00:00:01 |
| 3 | NESTED LOOPS | | 1001 | 81081 | 134 (2)| 00:00:01 |
| 4 | NESTED LOOPS | | 20 | 1200 | 43 (3)| 00:00:01 |
| 5 | VIEW | VW_NSO_1 | 20 | 100 | 22 (0)| 00:00:01 |
| 6 | HASH UNIQUE | | 20 | 180 | | |
|* 7 | CONNECT BY WITH FILTERING | | | | | |
| 8 | TABLE ACCESS BY INDEX ROWID | CU_ALL | 1 | 19 | 2 (0)| 00:00:01 |
|* 9 | INDEX UNIQUE SCAN | PK_CU_ALL_IND | 1 | | 1 (0)| 00:00:01 |
| 10 | NESTED LOOPS | | | | | |
| 11 | CONNECT BY PUMP | | | | | |
| 12 | TABLE ACCESS BY INDEX ROWID| CU_ALL | 20 | 180 | 22 (0)| 00:00:01 |
|* 13 | INDEX RANGE SCAN | IND2_CU_ALL | 20 | | 1 (0)| 00:00:01 |
| 14 | TABLE ACCESS BY INDEX ROWID | CU_ALL | 1 | 55 | 1 (0)| 00:00:01 |
|* 15 | INDEX UNIQUE SCAN | PK_CU_ALL_IND | 1 | | 0 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | IND_CA_RECEIPT_CUSTID | 50 | | 2 (0)| 00:00:01 |
Predicate Information (identified by operation id):
7 - access("CANO"=PRIOR "CUSTID")
9 - access("CUSTID"=2353)
13 - access("CANO"=PRIOR "CUSTID")
15 - access("CU"."CUSTID"="$nso_col_1")
16 - access("CA"."CUSTID"="CU"."CUSTID")
Statistics
1 recursive calls
0 db block gets
162 consistent gets
0 physical reads
0 redo size
2302 bytes sent via SQL*Net to client
379 bytes received via SQL*Net from client
5 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
52 rows processed
ALTER SESSION SET EVENTS '10053 trace name context off';The question might be asked, does the final SQL statement actually executed look the same as the original? Slightly reformatted:
The first SQL statement:
SELECT
CA.*,
CU.*
FROM
CA_RECEIPT CA,
CU_ALL CU
WHERE
CA.CUSTID = CU.CUSTID
AND CA.CUSTID IN (
SELECT
CUSTID
FROM
CU_ALL
START WITH
CUSTID = 2353
CONNECT BY PRIOR
CUSTID = CANO)
ORDER BY
ACCTYPE DESC;
Final Transformation:
SELECT
"CA"."CUSTID" "CUSTID",
"CA"."CAAMT" "CAAMT",
"CA"."CADT" "CADT",
"CA"."TOTBAL" "TOTBAL",
"CU"."CUSTID" "CUSTID",
"CU"."ADDR" "ADDR",
"CU"."PH" "PH",
"CU"."CANO" "CANO",
"CU"."ACCTYPE" "ACCTYPE"
FROM
(SELECT DISTINCT
"CU_ALL"."CUSTID" "$nso_col_1"
FROM
"TESTUSER"."CU_ALL" "CU_ALL"
WHERE
"CU_ALL"."CANO"=PRIOR "CU_ALL"."CUSTID"
CONNECT BY
"CU_ALL"."CANO"=PRIOR "CU_ALL"."CUSTID") "VW_NSO_1",
"TESTUSER"."CA_RECEIPT" "CA",
"TESTUSER"."CU_ALL" "CU"
WHERE
"CA"."CUSTID"="VW_NSO_1"."$nso_col_1"
AND "CA"."CUSTID"="CU"."CUSTID"
ORDER BY
"CU"."ACCTYPE" DESC;The second SQL statement:
SELECT
CA.*,
CU.*
FROM
CA_RECEIPT CA,
CU_ALL CU
WHERE
CA.CUSTID = CU.CUSTID
AND CU.CUSTID IN (
SELECT
CUSTID
FROM
CU_ALL
START WITH
CUSTID = 2353
CONNECT BY PRIOR
CUSTID = CANO)
ORDER BY
ACCTYPE DESC;
Final Transformation:
SELECT
"CA"."CUSTID" "CUSTID",
"CA"."CAAMT" "CAAMT",
"CA"."CADT" "CADT",
"CA"."TOTBAL" "TOTBAL",
"CU"."CUSTID" "CUSTID",
"CU"."ADDR" "ADDR",
"CU"."PH" "PH",
"CU"."CANO" "CANO",
"CU"."ACCTYPE" "ACCTYPE"
FROM
(SELECT DISTINCT
"CU_ALL"."CUSTID" "$nso_col_1"
FROM
"TESTUSER"."CU_ALL" "CU_ALL"
WHERE
"CU_ALL"."CANO"=PRIOR "CU_ALL"."CUSTID"
CONNECT BY
"CU_ALL"."CANO"=PRIOR "CU_ALL"."CUSTID") "VW_NSO_1",
"TESTUSER"."CA_RECEIPT" "CA",
"TESTUSER"."CU_ALL" "CU"
WHERE
"CA"."CUSTID"="CU"."CUSTID"
AND "CU"."CUSTID"="VW_NSO_1"."$nso_col_1"
ORDER BY
"CU"."ACCTYPE" DESC;Now, let's take a look at performance, flushing the buffer cache to force physical reads:
SET AUTOTRACE OFF
SET TIMING ON
SET AUTOTRACE TRACEONLY STATISTICS
SET ARRAYSIZE 100
ALTER SYSTEM FLUSH BUFFER_CACHE;
ALTER SYSTEM FLUSH BUFFER_CACHE;
SELECT
CA.*,
CU.*
FROM
CA_RECEIPT CA,
CU_ALL CU
WHERE
CA.CUSTID = CU.CUSTID
AND CA.CUSTID IN (
SELECT
CUSTID
FROM
CU_ALL
START WITH
CUSTID = 2353
CONNECT BY PRIOR
CUSTID = CANO)
ORDER BY
ACCTYPE DESC;
ALTER SYSTEM FLUSH BUFFER_CACHE;
ALTER SYSTEM FLUSH BUFFER_CACHE;
SELECT
CA.*,
CU.*
FROM
CA_RECEIPT CA,
CU_ALL CU
WHERE
CA.CUSTID = CU.CUSTID
AND CU.CUSTID IN (
SELECT
CUSTID
FROM
CU_ALL
START WITH
CUSTID = 2353
CONNECT BY PRIOR
CUSTID = CANO)
ORDER BY
ACCTYPE DESC;The output:
/* (with AND CA.CUSTID IN...) */
52 rows selected.
Elapsed: 00:00:00.64
Statistics
0 recursive calls
0 db block gets
232 consistent gets
592 physical reads
0 redo size
2044 bytes sent via SQL*Net to client
346 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
52 rows processed
/* (with AND CU.CUSTID IN...) */
52 rows selected.
Elapsed: 00:00:00.70
Statistics
0 recursive calls
0 db block gets
162 consistent gets
712 physical reads
0 redo size
2044 bytes sent via SQL*Net to client
346 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
52 rows processedThe original SQL statement completed in 0.64 seconds, and the second completed in 0.70 seconds.
Charles Hooper
IT Manager/Oracle DBA
K&M Machine-Fabricating, Inc. -
CBO not picking correct indexes or doing Full Scans
Database version - 10.2.0.4
OS : Solaris 5.8
Storage: SAN
Application : PeopleSoft Financials
DB size : 450 gb
DB server : 12 CPU ( 900 Mghz each ), 36 GB RAM
ASMM - sga_target_size = 5 gb
Locally managed tablespaces - MANUAL
- db_file_multiblock_read_count - not set explicitly in spfile ( implicitly defaulted to 128 )
- other optimizer related parameters are set to default
- system_statistics - CPUSPEEDNW=456.282722513089, IOSEEKTIM =10, IOTFRSPEED=4096
- dictionary object system stats were last gather in Nov 09
- stats on schema objs are gathered every night using custom script, but I have to say there are some histograms on some tables which were gathered by PS admins
begin
dbms_stats.gather_schema_stats(
ownname=> 'SCHEMANM' ,
cascade=> DBMS_STATS.AUTO_CASCADE,
estimate_percent=> DBMS_STATS.AUTO_SAMPLE_SIZE,
degree=> 10,
no_invalidate=> DBMS_STATS.AUTO_INVALIDATE,
granularity=> 'AUTO',
method_opt=> 'FOR ALL COLUMNS SIZE 1',
options=> 'GATHER STALE');
end;
Details :
We are experiencing erratic database performance. It was upgraded from 9i to 10g along with PS software upgrade. A job that runs on one day in 12 hrs(that is high in itself) would take more than 24 hrs another day.
We have Test and Staging envs on other servers which do not have performance issues of production magnitude. The test, staging dbs are clones of prod, created by ftp'ing files from one location to another, not sure if that makes any difference but just pointing out.
On Prod db some symptoms which baffle me are :
1) sql executing for over 40 minutes, check the plan and it is using an "incorrect" index, idx1. Hint sql with "correct" index, idx2, and it runs in few seconds. result set <400 rows. Cost with hint with idx2 is HIGHER. This scenario is still understandable as CBO is likely to pick a lower cost.
- But why is there so much discrepancy in cost and response time?
- what is influencing the CBO to pick an index which is obviously not the fastest response time?
2) sql plan shows FTS , execution time , runs forever . But a hint with index in this case shows the cost is LOWER and response time is in seconds, so why is CBO not even evaluating this index path? Because as I understand the CBO, it will always pick the lower cost plan.
What is influencing the CBO. Is it system stats? or any other database parameter? or the hardware ? the large SGA?? histogram ?? Stats gathering?? is there is any known issue with DBMS_STATS.AUTO_SAMPLE_SIZE and cardinaility?
Where should I put my focus?
What am I looking for ?
I do have Jonathan Lewis's Cost-Based Oracle Fundamentals which I have just started so perhaps I will be enlightened but while I read it, it would be of immense help to get some advice from forum gurus.
At this time I am not posting any exec plan or code, but I can do so if required.
Thanks,
JCPicking up just a couple of points - the ones about: why can performance change so much from one day to the next, and how can the optimizer miss a plan which (when hinted) shows a lower cost.
NOTE: These are only suggestions that may allow you to look at critical code and recognise the pattern of behaviour
Performance change:
You are using "gather stale" which means tables won't get new statistics is the volume of change since the last collection is "small". But peoplesoft tables can be big, so some tables may need a lot of data to change (which might take several days or weeks) before they get new stats. The 10g optimizer is able to compare the high-values stored with the predicate values supplied in queries, and decide that since the predicate is higher than the known highest value, it should scale down its estimates of data returned. After a few days when the stats haven't changed, the optimizer suddenly gets to the point where the estimated data size is much too small and the plan changes to something that you can see is bad. The typical example here is a date column that increases with time, and a query on "recent data" - the optimizer basically says: "you want 9th Feb - the high value says 28th Jan, there's virtually no data". Keeping date and sequence-based high-values up to date is important. (See dbms_stats.set_column_stats).
Lower cost plans available:
Sometimes this is a bug. Sometimes it's an unlucky side effect. When a query has a large number of tables in a single query block, the optimizer can only examine a limited subset of the possible join orders (for example, a 10-table join has over 3million join orders, and the default limit is 2,000 checked). Because of this limit, Oracle starts working through a few joins orders in a methodical manner, then does a "big jump" to a different set of join orders where it checks a few more join orders, then does another "big jump". It may be that it never gets to your nice plan with the lower cost because it doesn't have time. However, by putting in the hint, you may make some of the orders the optimizer would have examined drop out of the "methodical list" - so it examines a few more in one sequence, or possibly "jumps" to a different sequence that it would not othewise have reached. (I wrote a related blog item some time ago that might make this clearer, even though it's not about exactly the same phenomenon: http://jonathanlewis.wordpress.com/2006/11/03/table-order/ ).
Your recent comment about dynamic sampling is correct, by the way - by default (which for your version is is level 2 as a system parameter) it will only apply for tables which don't have any statistics. It's only for higher levels, or when explicitly hinted for tables, that it can apply to tables with existing statistics.
Regards
Jonathan Lewis
http://jonathanlewis.wordpress.com
http://www.jlcomp.demon.co.uk
"Science is more than a body of knowledge; it is a way of thinking"
Carl Sagan
To post code, statspack/AWR report, execution plans or trace files, start and end the section with the tag {noformat}{noformat} (lowercase, curly brackets, no spaces) so that the text appears in fixed format.
Maybe you are looking for
-
Hi experts actually i am ABAP guy .. i am going through Purchasing business scenario functiopnally , now learned from PO creation to Invoice my doubt is how can i proceed to make the payment againist the created invoice. i have cretaed purchsing -po
-
Need to reinstall Photoshop to the same imac
My imac received a new hard drive and photoshop has to be reinstalled. I need to make sure that I am still able to install it to another computer later on. I am able to use this on two computers and since this is the same computer, it needs to be c
-
Crm -isu integration , regulated scenarion
hello all , we are in process of crm isu integration for regulated scenario . crm 2007 / ecc 6 isu currently bp and BA are getting replicated . we are in process of replicating technical master data . however i need to know as we are in regulated ma
-
Question about operations allowed in methods of stateless and stateful bean
Hello, Can anyone tell me why ejbRemove and ejbCreate are allowed entreprise beans and resource manager access in stateful session beans and not in stateless session beans? Thanks in advance, Julien Martin.
-
Multiple account assignment in service entry sheet (ML81N)
Hi all, Is there any difference (other than the number of service entry sheet lines) if I create one service line in ML81N using the multiple account assignment screen with 2 different order numbers or 2 SES lines with single account assignment? Ther