From oracle-l-bounce@freelists.org Sun Feb 20 03:13:20 2005 Return-Path: Received: from air891.startdedicated.com (root@localhost) by orafaq.com (8.12.10/8.12.10) with ESMTP id j1K9DKUd001933 for ; Sun, 20 Feb 2005 03:13:20 -0600 X-ClientAddr: 206.53.239.180 Received: from turing.freelists.org (freelists-180.iquest.net [206.53.239.180]) by air891.startdedicated.com (8.12.10/8.12.10) with ESMTP id j1K9DKem001929 for ; Sun, 20 Feb 2005 03:13:20 -0600 Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 5B40D77051; Sun, 20 Feb 2005 03:12:05 -0500 (EST) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 21698-01; Sun, 20 Feb 2005 03:12:05 -0500 (EST) Received: from turing (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id C584976E82; Sun, 20 Feb 2005 03:12:04 -0500 (EST) DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=beta; d=gmail.com; h=received:message-id:date:from:reply-to:to:subject:mime-version:content-type:content-transfer-encoding; b=skuPeGASq8ck375D+qzlB9GTmILfRQghtiBN/TqMBkigDdx+CFBnh8E45d9CcrXCmY4sOdVZg5TKeHxA88uHPC2lQj5kP5dd2A/6JM7JH2JK1TwTueVSVUJ5PyHBtzrmAwtfVcSXtYXTos7wH11iPbZd5SQbpdxCP0DekG/oHG4= Message-ID: <9662496505022000107796f42a@mail.gmail.com> Date: Sun, 20 Feb 2005 00:10:24 -0800 From: Marc Slemko To: oracle-l@freelists.org Subject: performance problems updating dimension tables with MVs prejoined between fact and dimension Mime-Version: 1.0 Content-type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 8bit X-archive-position: 16457 X-ecartis-version: Ecartis v1.0.0 Sender: oracle-l-bounce@freelists.org Errors-To: oracle-l-bounce@freelists.org X-original-sender: identd@gmail.com Precedence: normal Reply-To: identd@gmail.com X-list: oracle-l X-Virus-Scanned: by amavisd-new-20030616-p9 (Debian) at avenirtech.net X-Spam-Checker-Version: SpamAssassin 2.60 (1.212-2003-09-23-exp) on air891.startdedicated.com X-Spam-Status: No, hits=0.0 required=5.0 tests=AWL,LINES_OF_YELLING autolearn=ham version=2.60 X-Spam-Level: We are having a bit of an annoying issue with a data warehouse we are currently in the process of deploying WRT some of the fast refresh materialized views we have. Running 10g. Due to the large size of some of our dimensions, we want to create materialized views that pre-join a fact table with a dimension table to pull one boolean attribute, for example, out of the dimension without having to blow up the size of the materialized view by having the actual id of the dimension table in it. This data warehouse is loaded more or less in realtime, throughout the day, so nearly all our materialized views are refresh on commit and fast refresh. We don't just add new fact table entries during the course of a day, but also load in new dimension records as necessary. Conceptually, this poses no problems for the rollups since the dimension data in question is never modified after insertion. However we are running into an implementation issue with Oracle that is causing this to be extremely ugly. When we do a COMMIT after adding a batch of records to the dimension, Oracle behind the scenes runs something like the following to update the materialized view: MERGE INTO "MARCS"."MV_LARGE" "SNA$" USING (SELECT /*+ OPT_ESTIMATE(QUERY_BLOCK MAX=1000) */ "MAS$1"."SMALL_D" "GB0", "DLT$0"."IS_SPECIAL" "GB1", SUM(1) "D0" FROM (SELECT /*+ CARDINALITY(MAS$ 1000) */ CHARTOROWID("MAS$"."M_ROW$$") RID$ , "MAS$"."IS_SPECIAL", "MAS$"."LARGE_D" FROM "MARCS"."MLOG$_LARGE" "MAS$" WHERE "MAS$".SNAPTIME$$ > :1 ) "DLT$0" , (SELECT "MAS$"."ROWID" "RID$" , "MAS$"."SMALL_D", "MAS$"."LARGE_D" FROM "MARCS"."FACT" "MAS$") AS OF SNAPSHOT (:2) "MAS$1" WHERE ("MAS$1"."LARGE_D"="DLT$0"."LARGE_D") GROUP BY "MAS$1"."SMALL_D","DLT$0"."IS_SPECIAL")"AV$" ON (SYS_OP_MAP_NONNULL("SNA$"."SMALL_D")=SYS_OP_MAP_NONNULL("AV$"."GB0") AND SYS_OP_MAP_NONNULL("SNA$"."IS_SPECIAL")=SYS_OP_MAP_NONNULL("AV$"."GB1")) WHEN MATCHED THEN UPDATE SET "SNA$"."COUNT(*)"="SNA$"."COUNT(*) "+"AV$"."D0" WHEN NOT MATCHED THEN INSERT ("SNA$"."SMALL_D", "SNA$"."IS_SPECIAL", "SNA$"."COUNT(*)") VALUES ( "AV$"."GB0", "AV$"."GB1", "AV$"."D0") Which ends up being optimized as: Rows Row Source Operation ------- --------------------------------------------------- 2 MERGE (cr=90996 pr=90930 pw=0 time=12304762 us) 0 PX COORDINATOR (cr=90996 pr=90930 pw=0 time=12304749 us) 0 VIEW (cr=0 pr=0 pw=0 time=0 us)(Orphan Entry) 0 HASH JOIN OUTER BUFFERED (cr=0 pr=0 pw=0 time=0 us) 0 BUFFER SORT (cr=0 pr=0 pw=0 time=0 us) 0 PX RECEIVE (cr=0 pr=0 pw=0 time=0 us) 0 VIEW (cr=90971 pr=90930 pw=0 time=12283633 us)(Orphan Entry) 0 SORT GROUP BY (cr=90971 pr=90930 pw=0 time=12283627 us) 0 HASH JOIN (cr=90971 pr=90930 pw=0 time=12283597 us) 1000 TABLE ACCESS FULL MLOG$_LARGE (cr=23 pr=0 pw=0 time=1106 us) 1000000 TABLE ACCESS FULL FACT (cr=90948 pr=90930 pw=0 time=2006047 us) 0 PX RECEIVE (cr=0 pr=0 pw=0 time=0 us) 0 PX BLOCK ITERATOR (cr=0 pr=0 pw=0 time=0 us)(Orphan Entry) 0 MAT_VIEW ACCESS FULL MV_LARGE (cr=0 pr=0 pw=0 time=0 us) Note the full table scan of the "fact" table. The optimizer appears to be making the correct decision here, since as far as it knows there are enough rows of the materialized view that would have to be updated based on the new records in the "large" dimension that a full table scan of the fact table is faster ... it just isn't being told that there really can't be any rows to update due to the foreign key constraint and the fact rows were only added. This becomes quite impractical with our larger fact tables. For example, with one dimension we have about 65 million fact table rows with 800k distinct dimension key values in the fact table, so you wouldn't have to actually update too many dimension records before the proper choice for the CBO would be to do the full table scan based on what it knows. When we do updates in very small batches, the optimizer picks an index lookup into the fact table instead, which is much faster since it doesn't take long to lookup something that doesn't exist in the index. I don't even know how I can add a hint to work around this, since the MERGE statement is generated by Oracle. Stored outlines don't seem an option because Oracle dynamically includes information about cardinality and blocks in the query text, which changes more or less with each commit. A related, but less important problem, is that if we update column "b" in a row in a dimension table that is prejoined to the fact table in a materialized view using column "a" of the dimension, Oracle still thinks it has to update all the rows in the materialized views related to the modified rows, even though column "b" isn't even in the materialized view log, let alone used in the materialized view. Has anyone run into this before or have any suggestions or other approaches that could accomplish the same thing? We really don't want to have to break the dimension out into multiple dimensions. We do have a TAR open, but have not been getting very useful results so far and are on a tight timeline. It can be a bit hard to explain exactly what is going on here, a full example, with schema, population scripts, sample sqltrace / tkprof output, etc. is at http://znep.com/~marcs/tmp/mvtest.tgz if anyone thinks they could offer some insight, a README.txt in that file contains details of the contents. Thanks for any comments. I'll post a followup if I figure anything out. -- http://www.freelists.org/webpage/oracle-l