Joe, I also have very recently trouble shooted a query performance problem wich contains a disjunctive subquery (OR + EXISTS) by re-writing the query so that unnesting the subquery will become an option for the CBO http://hourim.wordpress.com/2014/05/12/disjunctive-subquery/ This re-write allows the query to go from a massif 3,771,234 of consistent gets to just 8 buffer visits. Best regards Mohamed Houri www.hourim.wordpress.com 2014-05-13 16:41 GMT+02:00 Sweetser, Joe <JSweetser@xxxxxxxx>: > Wow, wow, wow. I am old enough nowadays to have the belief I have seen > it all (at least, in theory) but this suggestion/answer by Mr. Lewis was > truly eye-popping. The developer I have been working with had the same > reaction (but he’s much younger so that’s to be expected J ). Taking > Jonathan’s suggestion practically verbatim and making a few other minor > tweaks like breaking one delete statement into 2 separate ones, the run > time for this little program went from over 12 hours (and not even > finishing) to about 2.5 minutes. The buffer gets that were over a billion > for this particular delete dropped to 2.8 million. > > > > SSS3@idm3> @AdditionalInterestMigration.pls > > > > PL/SQL procedure successfully completed. > > > > Elapsed: 00:02:27.58 > > SSS3@idm3> > > > > It’s been said many times over the years but I will say it again: This > list is quite possibly the single best place on the internet to receive > timely, accurate, and valuable information about this little beast we call > Oracle. > > > > I have posted the explain plan for the revised statement below. Note the > overall cost dropped from 1096 to 13 (!) with Jonathan’s insight. I just > may have to take my “Oracle Core – Essential Internals for DBAs and > Developers” book next time JL visits Colorado in order to have it signed. > I thought my groupie days were over, but perhaps not. J > > > > Thanks again for the advice. > > -joe > > > > SQL stmt > > DELETE > > FROM BLDGASSIGNEDADDINT > > WHERE ID_ADDITIONALINTEREST in > > ( > > SELECT pk > > FROM ADDINTEREST > > WHERE ID_INSURED = :1 > > UNION ALL > > SELECT pk > > FROM ADDINTEREST > > WHERE lnnvl(ID_INSURED = :2) > > AND ID_POLICY in > > ( > > SELECT q.pk > > FROM quote q > > WHERE q.COMMONINSURED_ID = :3 > > AND q.ENDINFO_ID is null > > ) > > AND id_policy != :4 > > ) > > > > Explain plan > > DELETE STATEMENT Optimizer=ALL_ROWS (Cost=13 Cardinality=6 Bytes=144) > > DELETE OF BLDGASSIGNEDADDINT > > NESTED LOOPS (Cost=13 Cardinality=6 Bytes=144) > > VIEW OF VW_NSO_1 (VIEW) (Cost=10 Cardinality=3 Bytes=39) > > SORT (UNIQUE) (Cost=10 Cardinality=3 Bytes=62) > > UNION-ALL > > TABLE ACCESS (BY INDEX ROWID) OF ADDINTEREST (TABLE) (Cost=2 > Cardinality=1 Bytes=8) > > INDEX (RANGE SCAN) OF ADDINTERESTINSURED (INDEX) (Cost=1 > Cardinality=1) > > NESTED LOOPS > > NESTED LOOPS (Cost=8 Cardinality=2 Bytes=54) > > TABLE ACCESS (BY INDEX ROWID) OF QUOTE (TABLE) (Cost=5 > Cardinality=2 Bytes=28) > > INDEX (RANGE SCAN) OF QUOTE_COMN_INSRD_ID_IDX (INDEX) (Cost=3 > Cardinality=2) > > INDEX (RANGE SCAN) OF ADDINTERESTPOLICY (INDEX) (Cost=1 > Cardinality=2) > > TABLE ACCESS (BY INDEX ROWID) OF ADDINTEREST (TABLE) (Cost=2 > Cardinality=1 Bytes=13) > > INDEX (RANGE SCAN) OF BLDGASSIGNEDADDINT_BYADDINT (INDEX) (Cost=1 > Cardinality=2 Bytes=22) > > > > *From:* Jonathan Lewis [mailto:jonathan@xxxxxxxxxxxxxxxxxx] > *Sent:* Monday, May 12, 2014 2:00 PM > *To:* Sweetser, Joe; Jeffrey Beckstrom > > *Cc:* ORACLE-L > *Subject:* RE: SQL help > > > > > > > > Looks like an example of "subquery with OR" that forces a filter operation > and stops the optimiser from doing an unnest. See: > http://jonathanlewis.wordpress.com/2007/02/26/subquery-with-or > > > I think you'll probably have to rewrite the query to look something like: > > > delete from BLDGASSIGNEDADDINT where ID_ADDITIONALINTEREST in > (select pk from ADDINTEREST where ID_INSURED = :3 > union all > select pk from ADDINTEREST where lnnvl(ID_INSURED = :3) > and ID_POLICY in > (select q.pk from quote q where q.COMMONINSURED_ID = :1 and > q.ENDINFO_ID is null) > and id_policy != :2 > ); > > > > > > I think you'll also need an index on BLDGASSIGNEDADDINT(ID_ADDITIONALINTEREST) > since that's how you're trying to identify the rows for deletion. > > > > > > > Regards > Jonathan Lewis > http://jonathanlewis.wordpress.com > @jloracle > ------------------------------ > > *From:* oracle-l-bounce@xxxxxxxxxxxxx [oracle-l-bounce@xxxxxxxxxxxxx] on > behalf of Sweetser, Joe [JSweetser@xxxxxxxx] > *Sent:* 12 May 2014 20:39 > *To:* Jeffrey Beckstrom > *Cc:* ORACLE-L > *Subject:* RE: SQL help > > Forgot the index definitions…. > > There are indexes on: > > addinterest.pk, addinterest.id_insured, addinterest.id_policy > > and > > bldgassignedaddint.id_additionalinterest > > > > -joe > > *From:* Jeffrey Beckstrom [mailto:JBECKSTROM@xxxxxxxxx<JBECKSTROM@xxxxxxxxx>] > > *Sent:* Monday, May 12, 2014 1:07 PM > *To:* Sweetser, Joe > *Subject:* Re: SQL help > > > > Where's the index on id_policy for addinterest? > > >>> "Sweetser, Joe" <JSweetser@xxxxxxxx> 5/12/14 3:01 PM >>> > All, > > Without going into too much detail as to why (at this point), I have the > following statement: > > delete from BLDGASSIGNEDADDINT where ID_ADDITIONALINTEREST in > (select pk from ADDINTEREST where (ID_POLICY in > (select q.pk from quote q where q.COMMONINSURED_ID = :1 and q.ENDINFO_ID > is null) and id_policy != :2) > or ID_INSURED = :3); > > That yields an explain plan of this: > > DELETE STATEMENT Optimizer=ALL_ROWS (Cost=1096 Cardinality=2316 > Bytes=150540) > DELETE OF BLDGASSIGNEDADDINT > FILTER > HASH JOIN (Cost=1096 Cardinality=185659 Bytes=12067835) > TABLE ACCESS (FULL) OF ADDINTEREST (TABLE) (Cost=435 Cardinality=88384 > Bytes=3446976) > TABLE ACCESS (FULL) OF BLDGASSIGNEDADDINT (TABLE) (Cost=110 > Cardinality=185657 Bytes=4827082) > TABLE ACCESS (BY INDEX ROWID) OF QUOTE (TABLE) (Cost=3 Cardinality=1 > Bytes=39) > INDEX (UNIQUE SCAN) OF SYS_C005688632 (INDEX (UNIQUE)) (Cost=2 > Cardinality=1) > > That gets executed many times in a loop and is doing a boatload of logical > IO's and no physical IO's. By boatload I mean over 100 million buffer gets > each hour. > > I am trying to figure out a way to avoid the full table scans. Below are > the table creation statements for bldgassignaddint and addinterest tables > minus extraneous columns > > CREATE TABLE "BLDGASSIGNEDADDINT" > ( "ID_BUILDING" NUMBER(10), > "ID_ADDITIONALINTEREST" NUMBER(10), > CONSTRAINT "FK17A3EAC98DDD8F2C" FOREIGN KEY ("ID_ADDITIONALINTEREST") > REFERENCES "ADDINTEREST" ("PK") VALIDATE , > CONSTRAINT "FK17A3EAC9C50C5C52" FOREIGN KEY ("ID_BUILDING") REFERENCES > "BUILDING" ("PK") VALIDATE , > PRIMARY KEY ("ID_BUILDING", "ID_ADDITIONALINTEREST") VALIDATE; > > CREATE TABLE "ADDINTEREST" > ( "PK" NUMBER(10), > "ID_INSURED" NUMBER(10), > "ID_POLICY" NUMBER(10), > CONSTRAINT "FK4B56FACB277D71C9" FOREIGN KEY ("ID_INSURED") REFERENCES > "INSURED" ("PK") VALIDATE , > CONSTRAINT "FK4B56FACBE57638AB" FOREIGN KEY ("ID_POLICY") REFERENCES > "QUOTE" ("PK") VALIDATE , > PRIMARY KEY ("PK") VALIDATE ); > > Any suggestions? I am having no luck at all trying to incorporate EXISTS > instead of IN. > > 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 > > > > > > . > > -- Bien Respectueusement Mohamed Houri