Joe, The 2nd explain-plan definitely looks better than the first. Look at line #3 in the first explain-plan, below... --------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 41 | 87986 | 170 (1)| 00:00:03 | | 1 | COUNT | | | | | | |* 2 | FILTER | | | | | | | 3 | MAT_VIEW ACCESS FULL | ACCOUNTNOTEMVIEW | 40790 | 83M| 170 (1)| 00:00:03 | |* 4 | TABLE ACCESS BY INDEX ROWID | QUOTE | 1 | 15 | 4 (0)| 00:00:01 | |* 5 | INDEX RANGE SCAN | QUOTE_BY_OBJECTID | 1 | | 3 (0)| 00:00:01 | |* 6 | TABLE ACCESS BY INDEX ROWID| POL_POLICY | 1 | 16 | 4 (0)| 00:00:01 | |* 7 | INDEX RANGE SCAN | POL_POLICY_BY_OBJECTID | 3 | | 1 (0)| 00:00:01 | --------------------------------------------------------------------------------------------------------- It is estimated to retrieve 40,790 rows totalling 83Mb. Now look at the two similar steps in the 2nd explain-plan, lines 4-5 and 9-10 below, and total up the same numbers... ------------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1246 | 2611K| 106 (0)| 00:00:02 | | 1 | COUNT | | | | | | | 2 | CONCATENATION | | | | | | |* 3 | FILTER | | | | | | | 4 | MAT_VIEW ACCESS BY INDEX ROWID| ACCOUNTNOTEMVIEW | 623 | 1305K| 49 (0)| 00:00:01 | |* 5 | INDEX RANGE SCAN | JOE1 | 249 | | 44 (0)| 00:00:01 | |* 6 | TABLE ACCESS BY INDEX ROWID | POL_POLICY | 1 | 16 | 4 (0)| 00:00:01 | |* 7 | INDEX RANGE SCAN | POL_POLICY_BY_OBJECTID | 3 | | 1 (0)| 00:00:01 | |* 8 | FILTER | | | | | | | 9 | MAT_VIEW ACCESS BY INDEX ROWID| ACCOUNTNOTEMVIEW | 623 | 1305K| 49 (0)| 00:00:01 | |* 10 | INDEX RANGE SCAN | JOE1 | 249 | | 44 (0)| 00:00:01 | |* 11 | TABLE ACCESS BY INDEX ROWID | POL_POLICY | 1 | 16 | 4 (0)| 00:00:01 | |* 12 | INDEX RANGE SCAN | POL_POLICY_BY_OBJECTID | 3 | | 1 (0)| 00:00:01 | |* 13 | TABLE ACCESS BY INDEX ROWID | QUOTE | 1 | 15 | 4 (0)| 00:00:01 | |* 14 | INDEX RANGE SCAN | QUOTE_BY_OBJECTID | 1 | | 3 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------------------ Totalling lines 4-5 and 9-10, you see a total estimate of 1,246 table rows being retrieved after 498 index entries being retrieved (as opposed to 40,790 table rows being retrieved in the 1st explain-plan), and an estimated 2.61Mb of data being retrieved (as opposed to 83.00Mb of data being retrieved in the 1st explain-plan). While I don't think the "cost" metric calculated by the Oracle optimizer means anything in *absolute* terms, I think it means something in *comparative* terms in a situation like this. Here, we have the same SQL statement using two different plans, and for the 1st explain-plan the metric is 170 and for the 2nd explain-plan the metric is 106. The purpose of the "cost" metric is to provide a summarized point of comparison between plans. That in itself indicates that the 2nd explain-plan is "better" (i.e. less expensive) than the 1st, at least according to the estimations calculated by the cost-based optimizer. One can argue about how close the optimizer's estimations approach reality, but that "cost" metric is what makes the cost-based optimizer choose one explain-plan over another, so it is certainly worth using in this situation. Hope that makes sense? Please let me know what you think? Thanks! -Tim On 9/8/2011 3:53 PM, Sweetser, Joe wrote: > SQL gurus, > > I have a developer who came to me and asked me to make a certain sql > statement 'as fast as possible'. Said statement was running against a view > that was sort of nasty with sub-queries and a union thrown in. Cutting to > the chase, I created a MV that looks like this: > > SSS3@idm1> desc accountnotemview > Name Null? Type > ----------------------------------------- -------- > ---------------------------- > CREATED_USERNAME VARCHAR2(100) > CREATED_TIME TIMESTAMP(6) > OBJID VARCHAR2(50) > LINKTYPE VARCHAR2(100) > TASKORDER NUMBER > STATUS CHAR(7) > MESSAGE VARCHAR2(4000) > > Not a lot of data....36,474 rows. > SSS3@idm1> select count(*) from accountnotemview; > > COUNT(*) > ---------- > 36474 > > SQL statement is (ultimately, the accountID will be a bind variable): > SELECT rownum AS pk, > 128847 AS accountId, > NULL AS logid, > 0 AS deleted, > CREATED_TIME AS CREATEDATE, > CREATED_USERNAME AS USERNAME, > 'GENERAL' AS CATEGORY, > MESSAGE AS note > FROM accountnotemview acv > WHERE (linktype = 'Quote' > AND objid IN > (SELECT objectid FROM quote WHERE accountid = 128847 > )) > OR (linktype = 'Policy' > AND objid IN > (SELECT objectid FROM pol_policy WHERE accountid = 128847 AND logid = 1 > )) > / > > Explain plan is: > SSS3@idm1> @/opt/app/oracle/product/10.2.0/rdbms/admin/utlxpls.sql > > PLAN_TABLE_OUTPUT > --------------------------------------------------------------------------------------------------------- > Plan hash value: 3127273909 > > --------------------------------------------------------------------------------------------------------- > | Id | Operation | Name | Rows | > Bytes | Cost (%CPU)| Time | > --------------------------------------------------------------------------------------------------------- > | 0 | SELECT STATEMENT | | 41 | > 87986 | 170 (1)| 00:00:03 | > | 1 | COUNT | | | > | | | > |* 2 | FILTER | | | > | | | > | 3 | MAT_VIEW ACCESS FULL | ACCOUNTNOTEMVIEW | 40790 | > 83M| 170 (1)| 00:00:03 | > |* 4 | TABLE ACCESS BY INDEX ROWID | QUOTE | 1 | > 15 | 4 (0)| 00:00:01 | > |* 5 | INDEX RANGE SCAN | QUOTE_BY_OBJECTID | 1 | > | 3 (0)| 00:00:01 | > |* 6 | TABLE ACCESS BY INDEX ROWID| POL_POLICY | 1 | > 16 | 4 (0)| 00:00:01 | > |* 7 | INDEX RANGE SCAN | POL_POLICY_BY_OBJECTID | 3 | > | 1 (0)| 00:00:01 | > --------------------------------------------------------------------------------------------------------- > > I figured it might be a good idea to get rid of the full access of the MV so > I created an index: > SSS3@idm1> create index joe1 on accountnotemview (linktype); > > Index created. > > New explain is: > SSS3@idm1> @/opt/app/oracle/product/10.2.0/rdbms/admin/utlxpls.sql > > PLAN_TABLE_OUTPUT > ------------------------------------------------------------------------------------------------------------ > Plan hash value: 4264724585 > > ------------------------------------------------------------------------------------------------------------ > | Id | Operation | Name | Rows | > Bytes | Cost (%CPU)| Time | > ------------------------------------------------------------------------------------------------------------ > | 0 | SELECT STATEMENT | | 1246 | > 2611K| 106 (0)| 00:00:02 | > | 1 | COUNT | | | > | | | > | 2 | CONCATENATION | | | > | | | > |* 3 | FILTER | | | > | | | > | 4 | MAT_VIEW ACCESS BY INDEX ROWID| ACCOUNTNOTEMVIEW | 623 | > 1305K| 49 (0)| 00:00:01 | > |* 5 | INDEX RANGE SCAN | JOE1 | 249 | > | 44 (0)| 00:00:01 | > |* 6 | TABLE ACCESS BY INDEX ROWID | POL_POLICY | 1 | > 16 | 4 (0)| 00:00:01 | > |* 7 | INDEX RANGE SCAN | POL_POLICY_BY_OBJECTID | 3 | > | 1 (0)| 00:00:01 | > |* 8 | FILTER | | | > | | | > | 9 | MAT_VIEW ACCESS BY INDEX ROWID| ACCOUNTNOTEMVIEW | 623 | > 1305K| 49 (0)| 00:00:01 | > |* 10 | INDEX RANGE SCAN | JOE1 | 249 | > | 44 (0)| 00:00:01 | > |* 11 | TABLE ACCESS BY INDEX ROWID | POL_POLICY | 1 | > 16 | 4 (0)| 00:00:01 | > |* 12 | INDEX RANGE SCAN | POL_POLICY_BY_OBJECTID | 3 | > | 1 (0)| 00:00:01 | > |* 13 | TABLE ACCESS BY INDEX ROWID | QUOTE | 1 | > 15 | 4 (0)| 00:00:01 | > |* 14 | INDEX RANGE SCAN | QUOTE_BY_OBJECTID | 1 | > | 3 (0)| 00:00:01 | > ------------------------------------------------------------------------------------------------------------ > > Here is where I get lost. The original clock time against the original view > was about 1.5 seconds. The clock time against the materialized view is about > 0.5 seconds, with or without the index. These numbers were garnered simply > by 'set timing on' in > sqlplus. I can see that it is accessing fewer rows but it is also accessing > the MV twice by index (presumably once for each value > of linktype). > > My question is this: does the 2nd explain plan look any "better" than the > first? Since the timings are so close I am wondering if > it's just a wash because the amount of data is relatively small. > > Any/all comments welcome. > > Thanks, > -joe > Confidentiality Note: This message contains information that may be > confidential and/or privileged. If you are not the intended recipient, you > should not use, copy, disclose, distribute or take any action based on this > message. If you have received this message in error, please advise the sender > immediately by reply email and delete this message. Although ICAT Managers, > LLC, Underwriters at Lloyd's, Syndicate 4242, scans e-mail and attachments > for viruses, it does not guarantee that either are virus-free and accepts no > liability for any damage sustained as a result of viruses. Thank you. > > -- > //www.freelists.org/webpage/oracle-l > > > > > -- //www.freelists.org/webpage/oracle-l