<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-11995638</id><updated>2011-04-21T21:47:48.321-06:00</updated><title type='text'>Oracle Sponge -- Now Moved To Wordpress</title><subtitle type='html'>Please use http://oraclesponge.wordpress.com</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default?start-index=101&amp;max-results=100'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>191</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-11995638.post-115014817599781381</id><published>2006-06-12T15:31:00.000-06:00</published><updated>2006-06-12T15:36:16.140-06:00</updated><title type='text'>Moving to WordPress</title><content type='html'>Blogger irritates me. Let's see if Wordpress makes me happy.&lt;br /&gt;&lt;br /&gt;http://oraclesponge.wordpress.com/&lt;br /&gt;&lt;br /&gt;I've used the supplied import functionality to move over posts and comments, and it seems to have gone pretty well. Internal links need to be resolved to the new UR, and some text formatting has gone astray, but I can work my way through that.&lt;br /&gt;&lt;br /&gt;The category functionality is great, and the interface is much more snappy, so I'll probably stick with it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-115014817599781381?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/115014817599781381/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=115014817599781381' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/115014817599781381'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/115014817599781381'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/06/moving-to-wordpress.html' title='Moving to WordPress'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114927850221474674</id><published>2006-06-02T13:45:00.000-06:00</published><updated>2006-06-02T14:01:42.270-06:00</updated><title type='text'>Modelling of Condominiums</title><content type='html'>A condominium in this case being a geographical area of which two of more sovereignties agree to share dominium, but that title ought to do wonders for my statistics.&lt;br /&gt;&lt;br /&gt;Anyway, I was thinking about the mapping between cities and zip codes today, which is a many-to-many relationship, and the thought popped into my head, "I wonder if there are any cities which belong to multiple countries?" In other words, are there any cities which are part of a &lt;a href="http://en.wikipedia.org/wiki/Condominium_%28international_law%29"&gt;condominium&lt;/a&gt;?&lt;br /&gt;&lt;br /&gt;So I went looking for one, not expecting to find any, and I was right -- there appear to be none. Probably a good job too.&lt;br /&gt;&lt;br /&gt;In fact the only decent example of a condominium currently in effect seems to be that of &lt;a href="http://maps.google.com/maps?f=q&amp;hl=en&amp;amp;q=hendaye,+spain&amp;ll=43.342845,-1.765366&amp;amp;spn=0.001802,0.005364&amp;t=k&amp;amp;om=1"&gt;Pheasant Island&lt;/a&gt;, which is a condominium of France and Spain. It apparantly is shared on a six-monthly basis between the two nations, which leads to an interesting modelling problem -- a cyclic time-dependent relationship between geography and sovereignty. In other words, it's a time-share! (Stats again).&lt;br /&gt;&lt;br /&gt;Anyway, I'll leave that as "an exercise for the reader".&lt;br /&gt;&lt;br /&gt;It also raises anther question: back when one needed a passport to cross between the two countries, was a crime commited if a passport-less person was present on the island at the time that sovereignty changed? Perhaps none -- perhaps the condominium agreement allowed people of either nationality to be present on the island at any time, regardless of which state currently was in charge of it. But if the agreement did not allow this then could you charge a person with crossing a border if they were stationary at the time the offence occured?&lt;br /&gt;&lt;br /&gt;These thoughts usually turn-up on Fridays, oddly enough. Must be something to do with blood sugar.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114927850221474674?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114927850221474674/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114927850221474674' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114927850221474674'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114927850221474674'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/06/modelling-of-condominiums.html' title='Modelling of Condominiums'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114833259900024738</id><published>2006-05-22T15:08:00.000-06:00</published><updated>2006-05-22T15:16:39.073-06:00</updated><title type='text'>The Prime Number Few</title><content type='html'>I was chasing links through Wikipedia the other day, which always leads somewhere interesting.&lt;br /&gt;&lt;br /&gt;In this case I fell into the deep waters of linguistics and learned about &lt;a href="http://en.wikipedia.org/wiki/Garden_path_sentence"&gt;garden path sentences&lt;/a&gt;. They caught my eye in particular because the article includes one of my favourite jokes, albeit with a slightly different construction to my usual one.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;"If time flies like an arrow, do fruit flies like a banana?"&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Now that I've read a deconstruction of the joke, it seems a little less funny though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114833259900024738?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114833259900024738/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114833259900024738' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114833259900024738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114833259900024738'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/05/prime-number-few.html' title='The Prime Number Few'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114797136657075222</id><published>2006-05-18T07:00:00.000-06:00</published><updated>2006-05-18T12:50:26.886-06:00</updated><title type='text'>The Three Pillars of Oracle Data Warehousing</title><content type='html'>&lt;span style="font-weight: bold; font-style: italic;"&gt;Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is a basic topic for Oracle data warehousing beginners, based on some ideas that I'm hoping will stop buzzing round in my head if I commit them to virtual paper.&lt;br /&gt;&lt;br /&gt;There are three Oracle features that provide a foundation for successful data warehousing:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;P&lt;/span&gt;artitioning&lt;/li&gt;   &lt;li&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;P&lt;/span&gt;arallelism&lt;/li&gt;   &lt;li&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;P&lt;/span&gt;summary Tables (the "p" is silent)&lt;/li&gt; &lt;/ul&gt; Here are the benefits that they bring to the system.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Partitioning&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In a data warehouse we are interested in accessing large numbers of rows that are identified through some common attribute. Very often the same small numbers of attributes are used over and over again to filter the data. The most common is some form of date filter ("give me sales for&lt;span style="font-style: italic;"&gt; this &lt;/span&gt;&lt;span style="font-style: italic;"&gt;January&lt;/span&gt;"), and there are often others that are used very commonly ("give me inventory levels for &lt;span style="font-style: italic;"&gt;repairable&lt;/span&gt; items", "give me backorders for &lt;span style="font-style: italic;"&gt;California&lt;/span&gt;").&lt;br /&gt;&lt;br /&gt;In an OLTP system we would use an index or a full tablescan to get this subset of data, but that can be inefficient if we are selecting a large number of rows representing a subset of the total table data because of the high number of logical i/o's required and the single block reads that are used to access the table.&lt;br /&gt;&lt;br /&gt;In a data warehouse we can partition according to attributes commonly used as filters by the users, or according to logical child attributes of them (eg. users commonly filter by month but we partition by day).  This achieves two important aims.&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Rows of data that are commonly used together are physically co-located.&lt;/li&gt;   &lt;li&gt;The optimizer can treat each partition as a table and can perform fast scans of multiple partitions to access the data ("partition pruning").&lt;/li&gt; &lt;/ol&gt;We can also use multicolumn or composite partitioning to partition by multiple attributes, so that we can partition both by date and by location and get partition pruning on either or both.&lt;br /&gt;&lt;br /&gt;There are also benefits to manipulating bulk data -- we can use partition-based DDL operations to load and unload data from a table (a partition exchange) or to delete old data (partition drop or truncate).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Parallelism&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In a parallel query operation the physical locations in which the required rows are held are subdivided into a number of ranges, each of which is then scanned by a different process&lt;br /&gt;(a parallel query slave). The processes that read the data then pass it on to either a single query coordinator process or to another set of slaves which themselves pass the results to the query coordinator.&lt;br /&gt;&lt;br /&gt;Insert, update and delete operations can also be parallelized to provide faster bulk data changes.&lt;br /&gt;&lt;br /&gt;One of the key differences between serial and parallel queries are that the parallel queries read data directly from disk instead of checking for the required blocks in the SGAs block buffer area, and pass the result set directly to the user's PGA, thus completely bypassing the SGA. Read consistency is maintained through the query coordinator requesting a checkpoint to have commited dirty buffers of the scanned object written to disk before the PQ slaves start reading.&lt;br /&gt;&lt;br /&gt;The coordination required in creating and controlling query slaves leads to an overall increase in resource usage which can easily overload a system, but when correctly implemented spare system resources can be used to improve the response time of queries that access or manipulate a large amount of data.&lt;br /&gt;&lt;br /&gt;You probably need a lower degree of parallelism than you expect.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Psummary tables&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;OK, "summaries" then.&lt;br /&gt;&lt;br /&gt;The static nature of data warehouse data allows the results of some frequently executed queries to be pre-computed and cached as summary tables. These are often created through the Oracle materialized view object type, although the use of an MV is not mandatory.&lt;br /&gt;&lt;br /&gt;The query rewrite function of the cost-based optimizer can use the metadata stored in materialized view definitions or through declarations of query equivalence made through the DBMS_ADVANCED_REWRITE package (10g+ only)  to redirect queries against large base tables (typically data warehouse fact tables) to the smaller summary tables. In most cases the summary table does not have to be an exact match for the query.&lt;br /&gt;&lt;br /&gt;The major challenge in using summary tables is in finding an efficient mechanism for maintaining consistency between the summary and its base table(s).&lt;br /&gt;&lt;br /&gt;The major benefit is that almost any end-user query can be executed &lt;span style="font-style: italic;"&gt;extremely&lt;/span&gt; quickly with the correct use of summary tables.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;&lt;br /&gt;PSummary&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;Partitioning allows efficient access to relatively large subsets of data and efficient bulk manipulation of data.&lt;/li&gt;   &lt;li&gt;Parallelism allows the work of a single user process to be shared among multiple slave processes, leading to faster completion time but higher resource usage.&lt;/li&gt;   &lt;li&gt;Psummaries provide extremely fast performance, but their maintenance  and monitoring can require non-trivial efforts.&lt;/li&gt; &lt;/ul&gt; Now, hopefully these thoughts will leave my head alone.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114797136657075222?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114797136657075222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114797136657075222' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114797136657075222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114797136657075222'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/05/three-pillars-of-oracle-data.html' title='The Three Pillars of Oracle Data Warehousing'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114796446765379711</id><published>2006-05-18T06:00:00.000-06:00</published><updated>2006-05-18T13:11:49.956-06:00</updated><title type='text'>Strange Thing To Carry</title><content type='html'>My kids (3, 4 &amp; 6) intercepted and detained a pedestrian passing our house the other evening on the grounds that he was in Public Possession of Dogs, and they needed to subject him to the usual line of questioning: "Names?", "Ages?", "Boys or Girls?", "Do they bite?" etc..&lt;br /&gt;&lt;br /&gt;Strangely none of them noticed what I saw immediately, which was the holstered handgun on his hip. I'm sure he had a license to do so, but what he was expecting might happen to him in our Nice Suburban Neighborhood is anyone's guess.&lt;br /&gt;&lt;br /&gt;On the other hand one of my wife's co-workers reported a sighting of a &lt;a href="http://home.globalcrossing.net/%7Ebrendel/puma.html"&gt;mountain lion&lt;/a&gt; about two miles southeast of us a couple of years ago. I'm inclined to wonder whether *ahem* alcohol was a factor in that case because we're definitely on the wrong side of the city for that kind of wildlife -- antelope, deer, foxes and the occasional coyote maybe, but how a lion would pass unnoticed around &lt;a href="http://home.globalcrossing.net/%7Ebrendel/puma.html"&gt;Colorado Springs&lt;/a&gt; from the mountains on the west to the plains on the eastern side is a mystery to me.&lt;br /&gt;&lt;br /&gt;However the mountains to the west of us aparantly have the highest density of mountain lions throughout the Rockies, which leads to some &lt;a href="http://www.7522.com/page.php?code=34"&gt;basic precautions&lt;/a&gt; when hiking with the kids -- don't let them straggle or walk too far in front is all it really amounts to. (That link contains other interesting information on bubonic plague, hanta virus, avalanches etc. by the way). Sightings and other &lt;a href="http://www.denverpost.com/news/ci_3716178"&gt;less fortunate encounters&lt;/a&gt; seem to be &lt;a href="http://denver.yourhub.com/Story.aspx?contentid=85477"&gt;pretty common&lt;/a&gt; up around Boulder though.&lt;br /&gt;&lt;br /&gt;Here's a prime example of the kind of plump, tender morsel that a lion would enjoy most.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/8036/953/1600/DSC02479_sml.jpg"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/8036/953/320/DSC02479_sml.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It's amazing how fast those legs will carry him if he's told that there's a lion behind him!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114796446765379711?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114796446765379711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114796446765379711' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114796446765379711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114796446765379711'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/05/strange-thing-to-carry.html' title='Strange Thing To Carry'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114736936015522700</id><published>2006-05-11T11:14:00.000-06:00</published><updated>2006-05-11T11:48:27.986-06:00</updated><title type='text'>Getting the (Sub)Partition Name for a Row</title><content type='html'>Adapted from a response to a question posted on Oracle-l, here are three methods for finding out what partition or subpartition a table row is stored in, or which partition or subpartition a row will be stored in.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Logical Inference&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For range-based or list-based partitioning or for range-list composite partitioning it is often feasible to infer the partition or subpartition name from the values of the partition and subpartition key columns, as long as a sensible partition naming convention has been chosen.&lt;br /&gt;&lt;br /&gt;For example, for a range partitioned table defined in part by ...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Create table T (col1 date ...)&lt;br /&gt;Partition By Range (col1)&lt;br /&gt;(&lt;br /&gt;Partition Y2006_M01 values less than (date '2006-02-01'),&lt;br /&gt;Partition Y2006_M02 values less than (date '2006-03-01'),&lt;br /&gt;Partition Y2006_M03 values less than (date '2006-04-01'),&lt;br /&gt;...&lt;br /&gt;)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;...we can use a SQL function to provide the partition name:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;To_Char(col1,'"Y"YYYY"_M"MM')&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note the use of double-quotes in the above formula to identify literal strings in the date format.&lt;br /&gt;&lt;br /&gt;This is a fast and simple method, although an historically varying granularity on the partitions or a complex partitioning scheme could make it difficult to maintain.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;DBMS_MView.PMarker&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In cases where it is difficult or impossible to do perform the logical inference (hash partitioning, for example, or with complex multicolumn range/list partitioning) there are a couple of other techniques that you can use.&lt;br /&gt;&lt;br /&gt;In the DBMS_MVIEW package there is a PMARKER function that returns the data_object_id for the object in which the row resides, and you can join to user/dba/all_objects using that.&lt;br /&gt;&lt;br /&gt;Here's a funky example script using variable numbers of hash subpartitions ...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;drop table t&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;create table t (col1 , col2 , col3 )&lt;br /&gt;partition by range (col1)&lt;br /&gt;subpartition by hash (col2)&lt;br /&gt;(&lt;br /&gt;partition p1 values less than (2) subpartitions 2,&lt;br /&gt;partition p2 values less than (3) subpartitions 4,&lt;br /&gt;partition p3 values less than (4) subpartitions 8&lt;br /&gt;)&lt;br /&gt;as&lt;br /&gt;select mod(rownum,3)+1,&lt;br /&gt;      floor(dbms_random.value(1,256)),&lt;br /&gt;      floor(dbms_random.value(1,10))&lt;br /&gt;from   all_objects&lt;br /&gt;where rownum &lt; 101&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;with   obj as&lt;br /&gt;      (select --+ materialize&lt;br /&gt;              data_object_id,&lt;br /&gt;              subobject_name&lt;br /&gt;       from   user_objects&lt;br /&gt;       where  object_name = 'T' and&lt;br /&gt;              object_type = 'TABLE SUBPARTITION')&lt;br /&gt;select subobject_name,&lt;br /&gt;      col3&lt;br /&gt;from   T,&lt;br /&gt;      obj&lt;br /&gt;where  data_object_id = DBMS_MView.PMarker(t.rowid)&lt;br /&gt;order by 1&lt;br /&gt;/&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;My unsubstantiated guess is that this uses the file#/block# of the rowid to perform a look-up on the extent that contains the row. It therefore also ought to be possible to "hand-roll" a similar method based on extracting the file# and block# from the rowid's and joining to the dba/user/all_extents view (or a materialized subset of it, for performance reasons) to get the segment properties. I don't know if I'd care to go that route myself.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;TBL$OR$IDX$PART$NUM()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The TBL$OR$IDX$PART$NUM() function gives you the appropriate partition number for a table value or set of values. It's an undocumented (except through metalink, if that counts) function with a couple of magic numbers in it, but the general format to use is ...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;TBL$OR$IDX$PART$NUM("PARTITIONED_TABLE_NAME", 0, d#, p#, "COLUMN_NAME")&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The easiest way to get the appropriate format and magic numbers to use for this function is to run a trace on a "with validation" partition exchange against the table of interest, and you'll pretty much get the complete SQL that you need.&lt;br /&gt;&lt;br /&gt;So you might end up with something similar to ...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;with   utp as&lt;br /&gt;      (select --+ materialize&lt;br /&gt;              partition_position,&lt;br /&gt;              partition_name&lt;br /&gt;       from   user_tab_partitions&lt;br /&gt;       where  table_name = 'MY_TABLE')&lt;br /&gt;select utp.partition_name,&lt;br /&gt;      last_name,&lt;br /&gt;      first_name&lt;br /&gt;from   my_table,&lt;br /&gt;      utp&lt;br /&gt;where  utp.partition_position = TBL$OR$IDX$PART$NUM("MY_TABLE", 0, 0,&lt;br /&gt;65535, "PART_COL")&lt;br /&gt;/&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This method has the advantage that you can just supply it with arbitrary values for the partition key column(s) and you will get the appropriate partition number/name. Therefore you can use it to answer the question "Which partitions will these rows go into?". If you use partition exchanges "without validation" then you can also use it to run periodic checks on whether your ETL process has been putting rows in the wrong partitions.&lt;br /&gt;&lt;br /&gt;The disadvantage is that it is undocumented and has those pesky magic numbers, or course.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Summary&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;My preference is to use the method of logical inference, if possible.&lt;br /&gt;&lt;br /&gt;The other two are evidently based on very different methodologies -- one being based on the physical location of the row and the other on values of the partition key column(s), so they can be applied to different situations. The TBL$OR$IDX$PART$NUM method is rather more amenable to performance tuning by pre-aggregating the table data based on distinct partition keys prior to applying the function call.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114736936015522700?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114736936015522700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114736936015522700' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114736936015522700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114736936015522700'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/05/getting-subpartition-name-for-row.html' title='Getting the (Sub)Partition Name for a Row'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114667012289408531</id><published>2006-05-03T09:28:00.000-06:00</published><updated>2006-05-03T09:28:42.936-06:00</updated><title type='text'>Machine Music</title><content type='html'>Oooh, this is nice.&lt;br /&gt;&lt;br /&gt;http://video.google.com/videoplay?docid=-5503582578132361295&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114667012289408531?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114667012289408531/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114667012289408531' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114667012289408531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114667012289408531'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/05/machine-music.html' title='Machine Music'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114648980600201113</id><published>2006-05-01T06:39:00.000-06:00</published><updated>2006-05-01T07:23:29.186-06:00</updated><title type='text'>A Day Without Immigrants</title><content type='html'>So today is apparantly "&lt;a href="http://www.cnn.com/2006/US/05/01/immigrant.day/index.html"&gt;A Day Without Immigrants&lt;/a&gt;" and I just realised that this means me as well, technically speaking. Does it not seem strange that so immigrants should be held to be the source of so many problems in America, of all countries? And people in the southern border lands appear to be particularly prone to that finger-pointing, when they are living on land that was originally part of a Mexico too weakened by its own war for independence to be able to defend it from the young states to the north.&lt;br /&gt;&lt;br /&gt;I'm coming up to the eighth anniversary of my "stepping off the boat" as it were -- it's easy to work out as I just add on one year and a couple of days to my wedding anniversary, which is how long it took for my permanent resident visa to come through, plus a couple of weeks to get the last things packed and get a flight. I missed my first wedding anniversary by just five days I think. From the visa (and later job) interview questions I was asked I was apparantly suspected of being an economic migrant, which made the enormous paycut that I took to move from London, UK to Dayton, Ohio rather ironic.&lt;br /&gt;&lt;br /&gt;On the other hand, I don't really think of myself as an immigrant. I'm think I'm really someone who is just hanging out here for a while ... seeing the sights, doing a bit of shopping, being married, having kids etc..  On the other hand I've only been back to England once in all that time, for my brother's wedding in Cambridge last year.  With my parents living in Spain and my parents-in-law living near Rome we tend to pay fleeting visits to Heathrow every now and then just to see if they've finished building it yet (which they haven't) and to stock-up on the few goodies that are available there and not from our local Fine Imported Goods emporium -- ie. the commissary at Peterson AFB. They sell Flakes, Crunchies, Milk Chocolate Hobnobs etc, although they fly off the shelves because everyone panic-buys them apparantly.&lt;br /&gt;&lt;br /&gt;So anyway I get itchy feet everytime I see Oracle blogsters writing of their travels, and we're regularly overcome by an urge to move back to Europe. Any part of it at all will do. We were recently thwarted in an attempted move to Slovenia or Romania, and now we're trying for Germany. My brother tells me we should be moving to Denmark -- in fact a friend of a friend ended up there after some kind of incident involving rowing to Iceland in a replica of a Viking longboat, during which voyage he apparantly had an affair with the wife of the group leader which must have involved either extraordinary levels of discretion or some extraordinarily tense mealtimes -- but frankly it's probably Hobson's choice where we land. If the USAF doesn't have positions for a Developmental Engineer at least &lt;span style="font-style: italic;"&gt;available&lt;/span&gt; then it's not on the list.&lt;br /&gt;&lt;br /&gt;So where was I?&lt;br /&gt;&lt;br /&gt;Ah yes, the immigrant day thing. Well it turns out that most of my work colleagues will be in a Customer Acceptance Test for most of the day so they wouldn't notice me not being here (here being 1,200 miles from them) anyway. However, I applaud the priniciple and I may go down the Monica's Taco Shop for a breakfast burrito to show support for the cause.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114648980600201113?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114648980600201113/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114648980600201113' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114648980600201113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114648980600201113'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/05/day-without-immigrants.html' title='A Day Without Immigrants'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114631985535640065</id><published>2006-04-29T08:10:00.000-06:00</published><updated>2006-04-29T08:10:55.356-06:00</updated><title type='text'>Welcome</title><content type='html'>Welcome to the Dark Side, &lt;a href="http://markmal.blogspot.com/"&gt;Mark&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114631985535640065?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114631985535640065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114631985535640065' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114631985535640065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114631985535640065'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/welcome.html' title='Welcome'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114620010827713643</id><published>2006-04-27T22:47:00.000-06:00</published><updated>2006-04-27T22:57:23.803-06:00</updated><title type='text'>Whoops, security breach.</title><content type='html'>Well it turns out that thanks to "Homeland Security" your complete driver's license information may be on the Internet ... although the good news is that you can get it taken off. It seemed like &lt;span style="font-style: italic;"&gt;such&lt;/span&gt; a good idea that I've taken mine off.&lt;br /&gt;&lt;br /&gt;Go &lt;a href="http://www.license.shorturl.com/"&gt;here&lt;/a&gt;, search for it, and go through the "Hide my Records" procedure if it's there. What is wrong with these people?&lt;br /&gt;&lt;br /&gt;I already checked for George Bush of Texas, but I suppose there's a few of them and the "real" one isn't listed. If you're quick though (ie. quicker than him) you can get yourself a copy of the license of Mr Thomas Kyte of Leesburg, Virginia before he gets the records removed ... that's quite the photo!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114620010827713643?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114620010827713643/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114620010827713643' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114620010827713643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114620010827713643'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/whoops-security-breach.html' title='Whoops, security breach.'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114606917784856108</id><published>2006-04-26T10:28:00.000-06:00</published><updated>2006-04-26T10:32:57.913-06:00</updated><title type='text'>A Dose of Stupidity</title><content type='html'>Natural selection is a fine thing, but when a person's stupidity and arrogance takes someone else's life we can only hope that there will be some serious repurcussions.&lt;br /&gt;&lt;br /&gt;http://www.kcsg.com/story.aspx?id=682&lt;br /&gt;&lt;br /&gt;No helmet, no protective gear, and 85mph in a 35mph zone on a new machine? At the very least I hope this guy got skinned well enough that he'll need a helmet to get women to look at him in future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114606917784856108?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114606917784856108/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114606917784856108' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114606917784856108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114606917784856108'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/dose-of-stupidity.html' title='A Dose of Stupidity'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114605918140696676</id><published>2006-04-26T07:44:00.000-06:00</published><updated>2006-04-26T07:46:21.440-06:00</updated><title type='text'>More Security For You Sir.</title><content type='html'>http://www.computerworld.com/securitytopics/security/story/0,10801,110880,00.html&lt;br /&gt;&lt;br /&gt;Looks like some kind of security administrator role being introduced. $20,000 per CPU or $400 per user seems a littlesteep to me though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114605918140696676?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114605918140696676/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114605918140696676' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114605918140696676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114605918140696676'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/more-security-for-you-sir.html' title='More Security For You Sir.'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114545628042977377</id><published>2006-04-19T08:00:00.000-06:00</published><updated>2006-04-19T08:58:25.350-06:00</updated><title type='text'>Soon Time to Move Again</title><content type='html'>It's that time again, when the wife and I have to fill in forms and wishlists to try and influence our next posting. Last time we got pretty lucky - Colorado Springs wasn't on our list but it turned out pretty well.&lt;br /&gt;&lt;br /&gt;The eternal problem is that wherever there are Air Force bases, all commerce other than the defence industry tends to flee. It's a trend that is continuing, accelerating even, with the consolidation of Air Force units into the larger bases with plenty of room for growth -- ie. in the middle of a God-forsaken wilderness with a 60 mile commute to the nearest habitation.&lt;br /&gt;&lt;br /&gt;That isn't to say that they aren't good places to live -- &lt;a href="http://maps.google.com/maps?f=q&amp;hl=en&amp;amp;amp;q=eglin+afb&amp;ll=30.616131,-86.306165&amp;amp;spn=0.856828,1.733093&amp;t=h&amp;amp;om=1"&gt;Eglin AFB&lt;/a&gt; in Florida is next to one of the best beaches in the world, and &lt;a href="http://maps.google.com/maps?f=q&amp;hl=en&amp;amp;amp;q=eglin+afb&amp;ll=30.616131,-86.306165&amp;amp;spn=0.856828,1.733093&amp;t=h&amp;amp;om=1"&gt;Vandenburg AFB&lt;/a&gt; is nicely positioned on the California coast. Still they are not exactly major centres of commercial high-tech activity. In Colorado Springs I landed on my feet with a work-at-home contract with a longterm client, but that sort of thing wears thin after a while. Pretty quickly actually, especially in conjunction with a move to a new town.&lt;br /&gt;&lt;br /&gt;The current hot prospect looks like &lt;a href="http://maps.google.com/maps?f=q&amp;hl=en&amp;amp;q=hanscom+afb&amp;ll=42.459191,-71.272465&amp;amp;spn=0.367266,0.866547&amp;om=1"&gt;Hanscom AFB&lt;/a&gt;, just outside Boston, or maybe the Pentagon. I think I like the idea of Boston more. Actually I like the idea of Europe even more than that, with some interesting vacancies at &lt;a href="http://www.viamichelin.com/viamichelin/gbr/dyn/controller/mapPerformPage?pim=true&amp;amp;act=RefineToMap&amp;rnd=1145458184360&amp;amp;E_mg=210506110lS20J106109164947913616MAPB2C1a103gbr542000130u1103240000bcmFtc3RlaW400001100&amp;stat=ambiguous_map&amp;amp;strChoice=0"&gt;Ramstein&lt;/a&gt; to the south-west of Frankfurt -- I'll have to brush up on the non-existant German that I didn't learn from either the Turks I worked with in Munich or the girlfriend from Manchester I was living with at the time.&lt;br /&gt;&lt;br /&gt;Early days yet though, and the whole process just epitomises the story of the best-laid plans of mice and men often going astray. If the worst comes to the worst and we do end up in the middle of nowhere then I'll be hoping for at least some nearby reasonable-sized airport, and I'll do the road-warrior thing for a few years. Or we'll just find the wife a new employer who doesn't unreasonably insist on moving it's employees every three years or so, regardless of the diverse other opportunities in the area.  Tut! Maybe we'll move to New Zealand instead.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114545628042977377?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114545628042977377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114545628042977377' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114545628042977377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114545628042977377'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/soon-time-to-move-again.html' title='Soon Time to Move Again'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114538532313418478</id><published>2006-04-18T12:21:00.000-06:00</published><updated>2006-04-18T12:35:23.180-06:00</updated><title type='text'>Space Requirement for Compressed Row Updates</title><content type='html'>It seems that when you update rows within compressed blocks the data is temporarily decompressed then recompressed, possibly causing the table to grow.&lt;br /&gt;&lt;br /&gt;Here I create an uncompressed copy of DBA_OBJECTS, which takes 788 blocks to store. The compressed copy is then shown to take 256 blocks.&lt;br /&gt;&lt;br /&gt;On updating all of the rows the table has grown to 1038 blocks, approximately 256+788, yet as the DBMS_ROWID-based queries show the rows have not moved. It seems that an additional approximately-788 blocks of space have been added to move the table's high water mark.&lt;br /&gt;&lt;br /&gt;Curioser and curioser.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;SQL&gt; drop table t1&lt;br /&gt; 2 &lt;br /&gt;&lt;br /&gt;Table dropped.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; create table t1&lt;br /&gt; 2  nocompress&lt;br /&gt; 3  pctfree 0&lt;br /&gt; 4  as&lt;br /&gt; 5  select * from dba_objects&lt;br /&gt; 6  /&lt;br /&gt;&lt;br /&gt;Table created.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; exec dbms_stats.gather_table_stats(user,'T1')&lt;br /&gt;&lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select blocks,empty_blocks from user_tables&lt;br /&gt; 2  where table_name ='T1'&lt;br /&gt; 3  /&lt;br /&gt;&lt;br /&gt;   BLOCKS EMPTY_BLOCKS&lt;br /&gt;---------- ------------&lt;br /&gt;      788            0&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select min(dbms_rowid.rowid_block_number(rowid)) min_block,&lt;br /&gt; 2         max(dbms_rowid.rowid_block_number(rowid)) max_block,&lt;br /&gt; 3         count(distinct dbms_rowid.rowid_block_number(rowid)) num_blocks&lt;br /&gt; 4  from t1&lt;br /&gt; 5  /&lt;br /&gt;&lt;br /&gt;MIN_BLOCK  MAX_BLOCK NUM_BLOCKS&lt;br /&gt;---------- ---------- ----------&lt;br /&gt;  1610346    1611133        788&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; update t1 set owner = rtrim(owner)&lt;br /&gt; 2  /&lt;br /&gt;&lt;br /&gt;60120 rows updated.&lt;br /&gt;&lt;br /&gt;SQL&gt; commit&lt;br /&gt; 2  /&lt;br /&gt;&lt;br /&gt;Commit complete.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; exec dbms_stats.gather_table_stats(user,'T1')&lt;br /&gt;&lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select blocks,empty_blocks from user_tables&lt;br /&gt; 2  where table_name ='T1'&lt;br /&gt; 3  /&lt;br /&gt;&lt;br /&gt;   BLOCKS EMPTY_BLOCKS&lt;br /&gt;---------- ------------&lt;br /&gt;      788            0&lt;br /&gt;&lt;br /&gt;SQL&gt; select min(dbms_rowid.rowid_block_number(rowid)) min_block,&lt;br /&gt; 2         max(dbms_rowid.rowid_block_number(rowid)) max_block,&lt;br /&gt; 3         count(distinct dbms_rowid.rowid_block_number(rowid)) num_blocks&lt;br /&gt; 4  from t1&lt;br /&gt; 5  /&lt;br /&gt;&lt;br /&gt;MIN_BLOCK  MAX_BLOCK NUM_BLOCKS&lt;br /&gt;---------- ---------- ----------&lt;br /&gt;  1610346    1611133        788&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; drop table t1&lt;br /&gt; 2  /&lt;br /&gt;&lt;br /&gt;Table dropped.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; create table t1&lt;br /&gt; 2  compress&lt;br /&gt; 3  pctfree 0&lt;br /&gt; 4  as&lt;br /&gt; 5  select * from dba_objects&lt;br /&gt; 6  /&lt;br /&gt;&lt;br /&gt;Table created.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; exec dbms_stats.gather_table_stats(user,'T1')&lt;br /&gt;&lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select blocks,empty_blocks from user_tables&lt;br /&gt; 2  where table_name ='T1'&lt;br /&gt; 3  /&lt;br /&gt;&lt;br /&gt;   BLOCKS EMPTY_BLOCKS&lt;br /&gt;---------- ------------&lt;br /&gt;      256            0&lt;br /&gt;&lt;br /&gt;SQL&gt; select min(dbms_rowid.rowid_block_number(rowid)) min_block,&lt;br /&gt; 2         max(dbms_rowid.rowid_block_number(rowid)) max_block,&lt;br /&gt; 3         count(distinct dbms_rowid.rowid_block_number(rowid)) num_blocks&lt;br /&gt; 4  from t1&lt;br /&gt; 5  /&lt;br /&gt;&lt;br /&gt;MIN_BLOCK  MAX_BLOCK NUM_BLOCKS&lt;br /&gt;---------- ---------- ----------&lt;br /&gt;  1611146    1611401        256&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; update t1 set owner = rtrim(owner)&lt;br /&gt; 2  /&lt;br /&gt;&lt;br /&gt;60121 rows updated.&lt;br /&gt;&lt;br /&gt;SQL&gt; commit&lt;br /&gt; 2  /&lt;br /&gt;&lt;br /&gt;Commit complete.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; exec dbms_stats.gather_table_stats(user,'T1')&lt;br /&gt;&lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select blocks,empty_blocks from user_tables&lt;br /&gt; 2  where table_name ='T1'&lt;br /&gt; 3  /&lt;br /&gt;&lt;br /&gt;   BLOCKS EMPTY_BLOCKS&lt;br /&gt;---------- ------------&lt;br /&gt;     1038            0&lt;br /&gt;&lt;br /&gt;SQL&gt; select min(dbms_rowid.rowid_block_number(rowid)) min_block,&lt;br /&gt; 2         max(dbms_rowid.rowid_block_number(rowid)) max_block,&lt;br /&gt; 3         count(distinct dbms_rowid.rowid_block_number(rowid)) num_blocks&lt;br /&gt; 4  from t1&lt;br /&gt; 5  /&lt;br /&gt;&lt;br /&gt;MIN_BLOCK  MAX_BLOCK NUM_BLOCKS&lt;br /&gt;---------- ---------- ----------&lt;br /&gt;  1611146    1611401        256&lt;br /&gt;&lt;br /&gt;SQL&gt; update t1 set owner = lower(owner)&lt;br /&gt; 2  /&lt;br /&gt;&lt;br /&gt;60121 rows updated.&lt;br /&gt;&lt;br /&gt;SQL&gt; commit&lt;br /&gt; 2  /&lt;br /&gt;&lt;br /&gt;Commit complete.&lt;br /&gt;&lt;br /&gt;SQL&gt; exec dbms_stats.gather_table_stats(user,'T1')&lt;br /&gt;&lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt;&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select blocks,empty_blocks from user_tables&lt;br /&gt; 2  where table_name ='T1'&lt;br /&gt; 3  /&lt;br /&gt;&lt;br /&gt;   BLOCKS EMPTY_BLOCKS&lt;br /&gt;---------- ------------&lt;br /&gt;     1038            0&lt;br /&gt;&lt;br /&gt;SQL&gt; select min(dbms_rowid.rowid_block_number(rowid)) min_block,&lt;br /&gt; 2         max(dbms_rowid.rowid_block_number(rowid)) max_block,&lt;br /&gt; 3         count(distinct dbms_rowid.rowid_block_number(rowid)) num_blocks&lt;br /&gt; 4  from t1&lt;br /&gt; 5  /&lt;br /&gt;&lt;br /&gt;MIN_BLOCK  MAX_BLOCK NUM_BLOCKS&lt;br /&gt;---------- ---------- ----------&lt;br /&gt;  1611146    1611401        256&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114538532313418478?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114538532313418478/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114538532313418478' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114538532313418478'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114538532313418478'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/space-requirement-for-compressed-row.html' title='Space Requirement for Compressed Row Updates'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114537209022918816</id><published>2006-04-18T08:38:00.000-06:00</published><updated>2006-04-18T08:54:50.263-06:00</updated><title type='text'>Introspection time</title><content type='html'>I wandered over to &lt;a href="http://www.similarminds.com/index.html"&gt;Similar Minds&lt;/a&gt; to try their &lt;a href="http://similarminds.com/jung.html"&gt;Jung personality test&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div align="center"&gt;&lt;!--63.33 52.38 66.67 65.71--&gt; &lt;table bg="" style="color: rgb(221, 221, 221);" border="0" cellpadding="0" cellspacing="0"&gt; &lt;tbody&gt;&lt;tr&gt; &lt;td width="250"&gt; &lt;div align="center"&gt; &lt;span style="color:black;"&gt;&lt;b&gt;&lt;a href="http://similarminds.com/jung/istp.html"&gt;ISTP&lt;/a&gt;&lt;/b&gt; - "Engineer". Values freedom of action and following interests and impulses. Independent, concise in speech, master of tools. 5.4% of total population. &lt;/span&gt;&lt;/div&gt; &lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;a href="http://similarminds.com/"&gt;Free Jung Personality Test (similar to Myers-Briggs/MBTI)&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Apparantly it means &lt;a href="http://www.personalitypage.com/ISTP.html"&gt;this&lt;/a&gt;. some of those observations seem to be pretty spot-on -- ie. the one's that reflect well on me. Just ignore all the others, they're not true. Also the "athletic" thing, pay no attention to that.&lt;br /&gt;&lt;br /&gt;Careerwise I seem to be doing OK.  Here are some suggestions from the website:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Police and Detective Work&lt;/li&gt;   &lt;li&gt;Forensic Pathologists&lt;/li&gt;   &lt;li&gt;Computer Programmers, System Analysts and Computer Specialists&lt;/li&gt;   &lt;li&gt;Engineers&lt;/li&gt;   &lt;li&gt;Carpenters&lt;/li&gt;   &lt;li&gt;Mechanics&lt;/li&gt;   &lt;li&gt;Pilots, Drivers, Motorcyclists&lt;/li&gt;   &lt;li&gt;Athletes&lt;/li&gt;   &lt;li&gt;Entrepreneurs&lt;/li&gt; &lt;/ol&gt; Well, #3 there is obviously on target ... I also built a very nice fence and gate, and next I'm putting up some trellises so that's #5 ... I have a Masters degree in Aeronautical Engineering and an &lt;a href="http://en.wikipedia.org/wiki/Higher_National_Certificate"&gt;HNC&lt;/a&gt; in &lt;a href="http://www.warsashcentre.co.uk/"&gt;Marine Engineering&lt;/a&gt;, so that's #4 ... I ride a 2005 Triumph Tiger, #7.  I really ought to work harder on #8 though.&lt;br /&gt;&lt;br /&gt;OK, back to work people.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114537209022918816?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114537209022918816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114537209022918816' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114537209022918816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114537209022918816'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/introspection-time.html' title='Introspection time'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114523710504451866</id><published>2006-04-16T19:12:00.000-06:00</published><updated>2006-04-16T19:25:05.086-06:00</updated><title type='text'>Bad Form</title><content type='html'>I just finished filling in the thirteen-pages of forms required to transfer Number Three Son to a new day care. Here are some statistics on the number of times the forms required particular information&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;His name: Seven&lt;/li&gt;   &lt;li&gt;His date of birth: Four&lt;/li&gt;   &lt;li&gt;His current age: Two&lt;/li&gt;   &lt;li&gt;His doctor's name: Three&lt;br /&gt;  &lt;/li&gt;   &lt;li&gt;My address: Seven&lt;/li&gt;   &lt;li&gt;My phone number: Ten&lt;br /&gt;  &lt;/li&gt;   &lt;li&gt;My signature: &lt;span style="font-style: italic; font-weight: bold;"&gt;Eighteen&lt;/span&gt;&lt;/li&gt; &lt;/ul&gt; Things I have now lost as a result:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;Use of my writing hand&lt;/li&gt;   &lt;li&gt;Memory of my social security number&lt;br /&gt;  &lt;/li&gt;   &lt;li&gt;Last trace of sympathy for de-normalisation for performance&lt;/li&gt; &lt;/ul&gt; And my will to live is fading fast ... there must be a beer around here somewhere ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114523710504451866?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114523710504451866/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114523710504451866' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114523710504451866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114523710504451866'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/bad-form.html' title='Bad Form'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114495673835712041</id><published>2006-04-13T07:00:00.000-06:00</published><updated>2006-04-13T13:44:20.116-06:00</updated><title type='text'>In Praise of ISO 8601</title><content type='html'>As a UK ex-patriate and US resident I'm very sensitive to date formats. Moving from the DD/MM/YYY format to the MM/DD/YYYY format was a traumatic experience, and after eight years I still get a nervous twitch when I need to place the month before the day. What kind of a twisted mind thought that up?&lt;br /&gt;&lt;br /&gt;Probably the same one who decided that in my first job in the US I'd be dealing with a system for which the preferred date display formats were to be YYDDD and YYYYDDD. There can't be many people who are instinctively aware that the first of October is day 274 of a non-leap year, but if you find someone who is then I can tell you who they work for. Furthermore, they may belive that this data format is known as the Julian Date, and they're wrong about that of course. Further-furthermore it's surprising how many database designers believe that a requirement to display a date in YYYYDDD format means that it is a great idea to store it as a NUMBER(7), leading to it being displayed by default in many tools as "2,006,274.00". Actually it's not surprising, it's just irritating for the hopefully-obvious reasons.&lt;br /&gt;&lt;br /&gt;The other exception to the adherence to the MM/DD/YYYY format was the Immigration Service, who seemed to prefer DD/MM/YYYY on their forms. Thus I was lulled into a false sense of security through the whole visa process, and only ambushed with the MM/DD/YYYY abomination when I was fully commited to the process.&lt;br /&gt;&lt;br /&gt;This is why I have such a liking for &lt;a href="http://hydracen.com/dx/iso8601.htm"&gt;ISO 8601&lt;/a&gt;, which specifies the standard date format to be YYYY-MM-DD, with a reduced precision option of YYYY-MM and an optional time component of what we Oracleers would represent as hh24:mi:ss. I could lay out a complete set of reasons why this makes more sense but it is done very well &lt;a href="http://www.cl.cam.ac.uk/%7Emgk25/iso-time.html"&gt;here&lt;/a&gt;, and the display of week numbers is also nicely handled.&lt;br /&gt;&lt;br /&gt;Now then, do you suppose that if the massed hordes of database developers and administrators rose up against the MM/DD/YYYY and the less-objectionable DD/MM/YYYY and DD-Mon-YYYY formats in favour of YYYY-MM-DD then we might make a meaningful impact on this scourge? I'd hope so. If we all started a "Movement Against Date Display Stupidity" (MADDS)  by claiming that there was a fatal bug in the system when displaying anything other than YYYY-MM-DD then we might deceive our way to virtue, and all mankind would benefit.&lt;br /&gt;&lt;br /&gt;It'd do me a power of good, anyway.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114495673835712041?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114495673835712041/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114495673835712041' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114495673835712041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114495673835712041'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/in-praise-of-iso-8601.html' title='In Praise of ISO 8601'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114485617437467889</id><published>2006-04-12T07:00:00.000-06:00</published><updated>2006-04-12T09:43:30.516-06:00</updated><title type='text'>A Quick Materialized View Performance Note</title><content type='html'>I was asked in an email this morning about how to improve materialized view refresh performance, and it's something that appears in Google hits for the blog quite frequently. So I thought I'd write a quick-and-dirty posting to summarise some of the research (and the resulting practical applications) that I've been fiddling with recently.&lt;br /&gt;&lt;br /&gt;Here are some bullet points:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The materialized view fast refresh mechanism is a one-size-fits-all solution, and is probably not efficient for 99% of summary table maintenance operations.&lt;/li&gt;&lt;li&gt;The join of the aggregated change data to the MV is function-based, as the columns of both relations are wrapped in the &lt;a href="http://oraclesponge.blogspot.com/2005/11/optimizing-materialized-views-part-iii.html"&gt;Sys_Op_Map_NonNull&lt;/a&gt;() function that allows "null = null" joins. I think that it is extremely unlikely that anyone has nullable attribute columns in their fact or summary tables, so this (and the composite function-based index required to support it) are a waste of resources.&lt;/li&gt;&lt;li&gt;Because of the nature of the join it seems to be extremely unlikely that &lt;a href="http://www.blogger.com/posts.g?blogID=11995638"&gt;partition pruning&lt;/a&gt; of the summary table could take place.&lt;/li&gt;&lt;li&gt;The join mechanism promotes nested loop joins, where a hash join is probably more efficient (that's technically an outer join in the merge, of course).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The refresh mechanism assumes that a merge will be required, when sometimes an insert is not only possible but is very much more efficient.&lt;/li&gt;&lt;/ol&gt;If performance (and robustness, IMHO) are an issue for you then I would advise that you do the following:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Use materialized views only for enabling query rewrite (which means creating them on a prebuilt summary table, and unless you are loading to the summary by partition exchange then you have to drop the MV, refresh the summary table, and recreate the MV). In 10g it is much more easy to use the &lt;a href="http://download-west.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_advrwr.htm#i999507"&gt;DBMS_Advanced_Rewrite&lt;/a&gt; package instead of MV's.&lt;/li&gt;&lt;li&gt;Write your own refresh code, based on the usual principles of writing good SQL. If you don't need a merge then &lt;a href="http://oraclesponge.blogspot.com/2005/11/optimizing-materialized-views-part-iii.html"&gt;don't use it&lt;/a&gt;. If you don't need to join to dimension tables to get higher attributes then don't do it.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Leverage different levels of aggregation to help produce higher levels. For a series of hierarchical summaries, &lt;a href="http://oraclesponge.blogspot.com/2005/12/optimizing-materialized-views-part-iv.html"&gt;multi-level aggregations&lt;/a&gt; can be extremely beneficial.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Consider storing the refresh and MV definition SQL in CLOB columns of a summary management table, so they can be tuned and edited without needing to open up package code to do so.&lt;/li&gt;&lt;li&gt;Consider using a complete refresh, either through MV's or manually, for higher aggregation levels, particularly when you can reference another summary table to do so.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;My practical experience of taking this path delivered a reduction in the refresh time of a set of seven materialized views based on a single fact table, from a couple of hours down to six minutes. The publication of this is an example of what my client's technical lead calls "polishing the crown" :D&lt;br /&gt;&lt;br /&gt;Anyway, this is all a sort-of abstract from a whitepaper that I'm working on right now, which will include all sorts of proofs and demonstrations of the above, plus some process and risk management advice, but it doesn't look like it'll be ready very soon. Feel free to comment or ask questions on the points raised above though -- I don't want anyone to be kept in suspenders 'till the paper is finished.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114485617437467889?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114485617437467889/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114485617437467889' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114485617437467889'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114485617437467889'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/quick-materialized-view-performance.html' title='A Quick Materialized View Performance Note'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114444711866754421</id><published>2006-04-07T15:37:00.000-06:00</published><updated>2006-04-07T16:03:07.976-06:00</updated><title type='text'>My Dishwasher is List Partitioned</title><content type='html'>My dishwasher has two levels in it. The bottom level is for plates and Large Things, the top level is for cups and Small Things, and there is a removable cutlery partition attached to the door.&lt;br /&gt;&lt;br /&gt;If I had a spare cutlery partition then I could keep one of them in use by the dishwashing system while the other one is treated as a regular cutlery holder, and it could be filled with dirty cutlery as the items become available. When it was full I could perform a cutlery partition exchange between the one with clean items and the one now full of dirty items.&lt;br /&gt;&lt;br /&gt;If I had spare levels then they could be treated in a similar manner. I believe that commercial dishwashers have exactly that configuration, thus they operate with lower downtime because of this exchange mechanism, although the overall configuration requires more space.&lt;br /&gt;&lt;br /&gt;Within the cutlery partition there are six subpartitions. I like to fill each one with a single type of cutlery -- one for knives, two for spoons (they don't stack as well), a couple for forks, and one for other items. Although it is more work to separate the items into these subpartitions it has the advantage of physically clustering all the spoons together and I can access all items of one type without having to scan the complete cutlery partition.&lt;br /&gt;&lt;br /&gt;For the upper and lower levels similar principles apply, although they are not really subpartitioned in the same way. Instead the large plates are clustered in a single contiguous range -- the small plates, the glasses and the mugs each have their own place. Again it is more work to insert the items like this, but the advantage of faster retrieval is similar because I don't have to scan the complete level to pick similar items out from dissimilar ones. &lt;br /&gt;&lt;br /&gt;That is all.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114444711866754421?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114444711866754421/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114444711866754421' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114444711866754421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114444711866754421'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/my-dishwasher-is-list-partitioned.html' title='My Dishwasher is List Partitioned'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114434733061041066</id><published>2006-04-06T11:53:00.000-06:00</published><updated>2006-04-06T12:15:30.690-06:00</updated><title type='text'>The State of The Sponge</title><content type='html'>I notice that the blog just passed it's 80,000 page load since I started using Statcounter to monitor it, and that's just one day short of its first anniversary so it's time for stats.&lt;br /&gt;&lt;br /&gt;Looking at the statistics for the last 1000 visits, one-third of them come from Google searches -- most seem to be to do with materialized views, oddly enough.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;186 www.google.com   &lt;br /&gt;77  tkyte.blogspot.com   &lt;br /&gt;23  www.google.co.uk   &lt;br /&gt;23  www.bloglines.com   &lt;br /&gt;20  oracledoug.blogspot.com   &lt;br /&gt;19  www.google.co.in   &lt;br /&gt;14  www.google.com.au   &lt;br /&gt;10  www.google.ca   &lt;br /&gt;9   www.google.fr   &lt;br /&gt;8   thinkoracle.blogspot.com   &lt;br /&gt;7   blogs.oracle.com   &lt;br /&gt;7   orawin.info   &lt;br /&gt;6   www.google.de   &lt;br /&gt;6   oradot.com   &lt;br /&gt;6   www.rittman.net   &lt;br /&gt;5   www.google.es   &lt;br /&gt;5   www.blogger.com   &lt;br /&gt;5   www.petefinnigan.com   &lt;br /&gt;4   my5.statcounter.com   &lt;br /&gt;4   www.google.be&lt;br /&gt;4   www.google.it   &lt;br /&gt;4   search.blogger.com   &lt;br /&gt;4   www.newsgator.co.uk   &lt;br /&gt;4   www.netvibes.com   &lt;br /&gt;3   www.google.com.tr   &lt;br /&gt;3   www.google.fi   &lt;br /&gt;3   uk.my.yahoo.com   &lt;br /&gt;3   www.edpadgett.com   &lt;br /&gt;3   ora-dev.blogspot.com   &lt;br /&gt;3   search.msn.com   &lt;br /&gt;3   www.google.se   &lt;br /&gt;2   www.google.com.sg   &lt;br /&gt;2   www.google.co.il   &lt;br /&gt;2   www.oracle-base.com   &lt;br /&gt;2   www.google.ru   &lt;br /&gt;2   www.google.ro   &lt;br /&gt;2   www.google.ch   &lt;br /&gt;2   search.yahoo.com   &lt;br /&gt;2   pjs-random.blogspot.com   &lt;br /&gt;2   www.google.ie&lt;br /&gt;2   bloglines.com   &lt;br /&gt;2   www.google.com.ph   &lt;br /&gt;2   www.google.nl   &lt;br /&gt;2   oracle-base.com   &lt;br /&gt;2   discuss.joelonsoftware.com   &lt;br /&gt;2   www.google.com.sg   &lt;br /&gt;1   blogsearch.google.com   &lt;br /&gt;1   www.dbasupport.com   &lt;br /&gt;1   my2.statcounter.com   &lt;br /&gt;1   oramossoracle.blogspot.com   &lt;br /&gt;1   www.nomad8.com   &lt;br /&gt;1   www.google.co.za   &lt;br /&gt;1   my.yahoo.com   &lt;br /&gt;1   www.google.com.tw   &lt;br /&gt;1   www.google.com.hk   &lt;br /&gt;1   www.google.pl   &lt;br /&gt;1   www.google.co.kr   &lt;br /&gt;1   tkyte-test.blogspot.com   &lt;br /&gt;1   www.google.is   &lt;br /&gt;1   www.google.cl&lt;br /&gt;1   idyller.blogspot.com   &lt;br /&gt;1   www.google.com.ar   &lt;br /&gt;1   www.google.co.jp   &lt;br /&gt;1   peec2006.blogspot.com   &lt;br /&gt;1   www.google.com.br   &lt;br /&gt;1   www.google.gr   &lt;br /&gt;1   portal.umbrialistens.com   &lt;br /&gt;1   www.google.co.ve   &lt;br /&gt;1   kdsatplay.blogspot.com   &lt;br /&gt;1   www.google.dk   &lt;br /&gt;1   www.google.com.eg   &lt;br /&gt;1   oraqa.com   &lt;br /&gt;1   www.google.com.co   &lt;br /&gt;1   ambigramania.blogspot.com   &lt;br /&gt;1   www.google.pt   &lt;br /&gt;1   www.surfwax.com   &lt;br /&gt;1   www.google.com.mx   &lt;br /&gt;1   www.alltheweb.com&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Fifty-two countries are represented, if we ignore the unknowns ...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;402 41.66%   United States&lt;br /&gt;132 13.68%   United Kingdom&lt;br /&gt;80   8.29%   Canada&lt;br /&gt;60   6.22%   Lithuania&lt;br /&gt;39   4.04%   Netherlands&lt;br /&gt;37   3.83%   India&lt;br /&gt;26   2.69%   Australia&lt;br /&gt;20   2.07%   Germany&lt;br /&gt;17   1.76%   France&lt;br /&gt;15   1.55%   Switzerland&lt;br /&gt;13   1.35%   Spain&lt;br /&gt;11   1.14%   Unknown   -&lt;br /&gt;9    0.93%   Russian Federation&lt;br /&gt;8    0.83%   Belgium&lt;br /&gt;7    0.73%   Turkey&lt;br /&gt;7    0.73%   Japan&lt;br /&gt;6    0.62%   Norway&lt;br /&gt;6    0.62%   Denmark&lt;br /&gt;5    0.52%   Portugal&lt;br /&gt;4    0.41%   United Arab Emirates&lt;br /&gt;4    0.41%   Italy&lt;br /&gt;4    0.41%   Sweden&lt;br /&gt;4    0.41%   Israel&lt;br /&gt;3    0.31%   Colombia&lt;br /&gt;3    0.31%   Greece&lt;br /&gt;3    0.31%   Singapore&lt;br /&gt;2    0.21%   Romania&lt;br /&gt;2    0.21%   Philippines&lt;br /&gt;2    0.21%   Poland&lt;br /&gt;2    0.21%   Austria&lt;br /&gt;2    0.21%   Ireland&lt;br /&gt;2    0.21%   Serbia And Montenegro&lt;br /&gt;2    0.21%   Finland&lt;br /&gt;2    0.21%   Latvia&lt;br /&gt;2    0.21%   Bolivia&lt;br /&gt;2    0.21%   Uruguay&lt;br /&gt;2    0.21%   Argentina&lt;br /&gt;2    0.21%   South Africa&lt;br /&gt;2    0.21%   Puerto Rico&lt;br /&gt;1    0.10%   Pakistan&lt;br /&gt;1    0.10%   Bulgaria&lt;br /&gt;1    0.10%   Estonia&lt;br /&gt;1    0.10%   Kenya&lt;br /&gt;1    0.10%   Chile&lt;br /&gt;1    0.10%   Andorra&lt;br /&gt;1    0.10%   Ukraine&lt;br /&gt;1    0.10%   Iceland&lt;br /&gt;1    0.10%   New Zealand&lt;br /&gt;1    0.10%   Egypt&lt;br /&gt;1    0.10%   Brazil&lt;br /&gt;1    0.10%   Slovenia&lt;br /&gt;1    0.10%   Korea, Republic Of&lt;br /&gt;1    0.10%   Hong Kong&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Good to see the Netherlands up there this time! Readership seems to be up to 13 Dutch people, unless some of them are cheating and using multiple computers.&lt;br /&gt;&lt;br /&gt;The most frequently occuring city for Sponge readers is London, UK, then Calgary, Ontario, Arlington, Nieuwegein ...&lt;br /&gt;&lt;br /&gt;The most popular article is "Writing Good SQL". It's a perennial favourite with the Google crowd.&lt;br /&gt;&lt;br /&gt;That's all -- back to work people!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114434733061041066?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114434733061041066/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114434733061041066' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114434733061041066'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114434733061041066'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/state-of-sponge.html' title='The State of The Sponge'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114433277342415160</id><published>2006-04-06T08:12:00.000-06:00</published><updated>2006-04-06T08:12:53.510-06:00</updated><title type='text'>A Story of Database FUD</title><content type='html'>The sorry tale here ... http://discuss.joelonsoftware.com/default.asp?joel.3.328948.11&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114433277342415160?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114433277342415160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114433277342415160' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114433277342415160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114433277342415160'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/story-of-database-fud.html' title='A Story of Database FUD'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114427364599290102</id><published>2006-04-05T15:30:00.000-06:00</published><updated>2006-04-05T15:47:26.070-06:00</updated><title type='text'>Bad Advice On Materialized View Deferrable Constraints</title><content type='html'>An &lt;a href="http://www.jlcomp.demon.co.uk/MV_non_bug.html"&gt;article&lt;/a&gt; by Jonathan Lewis on constraint problems with materialized views set off a little bell in my head about a metalink document on the subject, &lt;a href="https://metalink.oracle.com/metalink/plsql/ml2_documents.showFrameDocument?p_database_id=NOT&amp;p_id=284101.1"&gt;Note 284101.1&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The note protests the use of unique, foreign key and primary key constraints on materialized views, and includes the following interesting phrases ...&lt;br /&gt;&lt;br /&gt;"&lt;em&gt;It is not a good idea to create unique (unique indexes ) constraints , primary key or Foreign key constraints on the snapshot base table ... There should not be any Unique/PK constraints at Mview base table ... Drop the Unique/PK constriants on Mview Base Tables&lt;/em&gt;."&lt;br /&gt;&lt;br /&gt;Then one of the workarounds is "&lt;em&gt;You can have Deferred Constraints&lt;/em&gt;". The document doesn't identify why having deferred constraints might be a bad idea, or why not having integrity constraints on the table at all is preferable to having them deferred .. I can't think of a reason why that might be so, and I can think of several reasons why it might not be so (query optimization being the prime one).&lt;br /&gt;&lt;br /&gt;All this misdirection and ambiguity, combined with the abbreviation of an error code from "ORA-00001" to "ORA-1" in the title of a help document (does that make sense to anyone?) make this a pretty poor piece of work. It's not the &lt;a href="http://oraclesponge.blogspot.com/2005/06/most-useless-metalink-article-ever.html"&gt;Most Useless Metalink Article Ever&lt;/a&gt;, but it's close.&lt;br /&gt;&lt;br /&gt;By the way, if you read the title and the first few words of this article, and thought "Dave's going to say that Jonathan Lewis gave bad advice!" before realising I wasn't ... the effect was intentional :D  If you didn't think that then my plan failed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114427364599290102?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114427364599290102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114427364599290102' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114427364599290102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114427364599290102'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/bad-advice-on-materialized-view.html' title='Bad Advice On Materialized View Deferrable Constraints'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114424345475933909</id><published>2006-04-05T07:16:00.000-06:00</published><updated>2006-04-05T07:24:18.296-06:00</updated><title type='text'>What's Wrong With Opera?</title><content type='html'>Not the musical form, obviously there's nothing wrong with that at all.&lt;br /&gt;&lt;br /&gt;The browser is very nice, but I can't read the Oracle forums with it. If I go &lt;a href="http://forums.oracle.com/forums/forum.jspa?forumID=260"&gt;here&lt;/a&gt; then clicking on any link takes me &lt;a href="http://www.oracle.com/errors/404.html"&gt;here&lt;/a&gt;. Opera also doesn't display the little images that are scattered all around the page, and I get a bunch of rectangles with text in them. Internet Explorer doesn't have this problem, nor the issues that I wrote about in Firefox the other day  (heresy, I know).&lt;br /&gt;&lt;br /&gt;Why is reading HTML and following links so difficult? You'd imagine that they'd have it close to working by now. Well, maybe there's some configuration thing that needs to be done to the browser, but I'm not sure why I should have to spend my time messing about with this kind of crap.&lt;br /&gt;&lt;br /&gt;OK, I promise to write something later this week about a technology that I do like. Um ....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114424345475933909?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114424345475933909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114424345475933909' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114424345475933909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114424345475933909'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/whats-wrong-with-opera.html' title='What&apos;s Wrong With Opera?'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114419980917132573</id><published>2006-04-04T19:15:00.000-06:00</published><updated>2006-04-04T19:16:49.210-06:00</updated><title type='text'>Development and Tuning</title><content type='html'>I had a pithy thought earlier today.&lt;br /&gt;&lt;br /&gt;1. Development is the business of making the database do work&lt;br /&gt;2. Tuning is the business of reducing the amount of work the database does.&lt;br /&gt;&lt;br /&gt;Therefore, tuning is the opposite of development. It is "anti-development"!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114419980917132573?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114419980917132573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114419980917132573' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114419980917132573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114419980917132573'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/development-and-tuning.html' title='Development and Tuning'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114407637787126061</id><published>2006-04-03T08:49:00.000-06:00</published><updated>2006-04-03T08:59:37.916-06:00</updated><title type='text'>What's Wrong With Firefox?</title><content type='html'>A number of things.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;On one of my machines it consistently refuses to open particular web sites. &lt;a href="http://www.dbdebunk.com/index.html"&gt;http://www.dbdebunk.com/index.html&lt;/a&gt; is one of them -- IE has no problem, Opera has no problem. No error message, nothing. It just seems to pretend that I haven't asked it do do anything.&lt;/li&gt;&lt;li&gt;It's a resource hog. Memory usage often tops 150Mb, and can only be reduced by stopping and restarting it. If my machine startys running slowly then I know where to look -- Firefox is sitting and chewing up CPU cycles to no apparant effect.&lt;/li&gt;&lt;li&gt;It's unstable. I generally get four or five crashes a week, and they're not associated with having a lot of windows or tabs open either.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;It didn't used to be this bad, and it seems to be getting worse. AdBlock has been the only reason to keep using it, but that's not enough anymore. I'd actually rather have adverts on the page than put up with the all of Firefox's crap .&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114407637787126061?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114407637787126061/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114407637787126061' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114407637787126061'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114407637787126061'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/04/whats-wrong-with-firefox.html' title='What&apos;s Wrong With Firefox?'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114375266425947943</id><published>2006-03-30T14:03:00.000-07:00</published><updated>2006-03-30T14:04:24.303-07:00</updated><title type='text'>URL Masking at DBASupport.com forums</title><content type='html'>http://www.dbasupport.com/forums/showthread.php?p=226665&lt;br /&gt;&lt;br /&gt;Rather sinister, I think. I wonder what's behind it?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(Busy day for posts today, huh?)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114375266425947943?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114375266425947943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114375266425947943' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114375266425947943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114375266425947943'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/03/url-masking-at-dbasupportcom-forums.html' title='URL Masking at DBASupport.com forums'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114375048728802398</id><published>2006-03-30T13:19:00.000-07:00</published><updated>2006-03-30T13:28:07.343-07:00</updated><title type='text'>Why Space Travel Is A Stupid Idea</title><content type='html'>It seems to me that all other arguments aside, when a &lt;a href="http://edition.cnn.com/2006/TECH/space/03/30/space.shuttle.reut/index.html"&gt;lamp falling&lt;/a&gt; onto the outside of a space ship and causing "&lt;span style="font-style: italic;"&gt;... five small indentations, with the largest about the size of a stick of gum, and one 6-inch (15-centimeter) to 7-inch (17-centimeter) long scratch&lt;/span&gt;" makes it onto the news, then it's time to be rethinking whether this is a goal worth pursuing. Doubtless at this very moment a ten-man committee is being formed to write a review of the "Procedures for Luminescent Output Device Restraint In Shuttle Proximity".&lt;br /&gt;&lt;br /&gt;Bonus opinion: I don't believe that the spokesman for the space shuttle's manufacturer, Lockheed Martin, is called Marion LaNasa. I think they made that up.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114375048728802398?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114375048728802398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114375048728802398' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114375048728802398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114375048728802398'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/03/why-space-travel-is-stupid-idea.html' title='Why Space Travel Is A Stupid Idea'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114374155585056734</id><published>2006-03-30T10:52:00.000-07:00</published><updated>2006-03-30T10:59:15.906-07:00</updated><title type='text'>Unfortunate Timing</title><content type='html'>My plans to attend UKOUG in November, and maybe even submit a paper, have been thoroughly sunk. Following the collapse of our plans to get posted to Eastern Europe, the wife is scheduled for a deployment to Sicily from October to December and I'll be playing the part of Mr. Mom to our herd of offspring for three months.&lt;br /&gt;&lt;br /&gt;Speaking of which, what's the collective noun for small boys? A wrestle of boys? A destruction? A puddle? Any of those would seem to fit.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114374155585056734?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114374155585056734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114374155585056734' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114374155585056734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114374155585056734'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/03/unfortunate-timing.html' title='Unfortunate Timing'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114367015767217328</id><published>2006-03-29T15:06:00.000-07:00</published><updated>2006-03-29T15:09:17.733-07:00</updated><title type='text'>Things I Need: Part I</title><content type='html'>Now that my Poweredge is up and running, I'm casting about for a New Shiny Thing that I absolutely must have.&lt;br /&gt;&lt;br /&gt;I'm unimpressed with mere &lt;a href="http://tkyte.blogspot.com/2006/03/these-gloves.html"&gt;items of technological clothing&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;What I need is a &lt;a href="http://www.amazon.com/exec/obidos/tg/detail/-/B00067F1CE/sr=8-1/qid=1143656608/ref=pd_bbs_1/104-6443492-8940715?%5Fencoding=UTF8&amp;amp;v=glance"&gt;JL421 Badonkadonk&lt;/a&gt;. Am I right fellas?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114367015767217328?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114367015767217328/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114367015767217328' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114367015767217328'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114367015767217328'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/03/things-i-need-part-i.html' title='Things I Need: Part I'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114343463034971211</id><published>2006-03-26T21:26:00.000-07:00</published><updated>2006-03-27T06:43:53.216-07:00</updated><title type='text'>A List Of Weekend Successes</title><content type='html'>A list of things we did this weekend&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Recommissioned sprinkler system, watered plant, soaked lawn, decommissioned sprinkler system&lt;/li&gt;&lt;li&gt;Cut kids' hair -- no fatal wounds inflicted.&lt;/li&gt;&lt;li&gt;Cleared basement&lt;/li&gt;&lt;li&gt;Got rid of four old tires&lt;/li&gt;&lt;li&gt;Made chicken and rice soup&lt;/li&gt;&lt;li&gt;Mended kite -- flew kite -- broke kite again&lt;/li&gt;&lt;li&gt;Boxed 10 cu.ft. of kids clothes, to go to Afghanistan via USAF apparantly.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Got Poweredge 6400 running on Centos 4, moved it to the basement &amp;amp; started Oracle 10.1 install.&lt;/li&gt;&lt;/ol&gt;OK, about item 8.&lt;br /&gt;&lt;br /&gt;The tricky part of the business was the boot. I had grub stage2read errors coming out the wazoo, and eventually gave up on trying "conventional" fixes. Booting with a floppy drive turned out to be the answer, as long as it referenced an initrd. Quite the learning experience.&lt;br /&gt;&lt;br /&gt;Note to self: make backup of floppy disk! Maybe two backups.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114343463034971211?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114343463034971211/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114343463034971211' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114343463034971211'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114343463034971211'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/03/list-of-weekend-successes.html' title='A List Of Weekend Successes'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114260681678520046</id><published>2006-03-17T07:45:00.000-07:00</published><updated>2006-03-17T07:46:56.790-07:00</updated><title type='text'>Poweredge 6400 -- the Great o/s Debate</title><content type='html'>First, some boring details.&lt;br /&gt;&lt;br /&gt;The service tag for this machine is H6MGN01, and the recorded configuration seems to be pretty accurate. The critical part is this: "ASSEMBLY, CARD (CIRCUIT), POWEREDGE EXPANDABLE RAID CONTROLLER NUMBER, 3-DC, 128"&lt;br /&gt;&lt;br /&gt;Maybe it's a truism that the tricky part of working with these systems is getting the drivers for the array loaded before the install, but I seem to have worked that out. There was a nervous moment of array errors before I realized that the controller card was slightly unseated during shipping, but that seems to be a non-issue now.&lt;br /&gt;&lt;br /&gt;Dell appear to have pretty good support for Linux, on the whole. I've been through the information at http://linux.dell.com/storage.shtml and deduced the following.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The PERC 3/DC requires a MegaRAID driver "megaraid_mbox"&lt;/li&gt;&lt;li&gt;The required driver is present in RHEL4 kernel 2.6.9-5.EL and higher -- sounds good for a Whitbox or Centos install!&lt;/li&gt;&lt;li&gt;SLES9 ought to work, but has not been tested on the PERC3 series by Dell&lt;/li&gt;&lt;li&gt;The PERC3/DC firmware update must be extracted to floppy on a Windows machine&lt;/li&gt;&lt;li&gt;There are Solaris drivers for the Adaptec card, but not for the PERC3. Boooh.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Point 1: no problem. Actually SuSE 8 appears to have the right drivers also. I tried a quick install yesterday evening but it choked on reboot with a "GRUB loading stage2Read error" -- maybe something needs tweaking there.&lt;br /&gt;&lt;br /&gt;Point 3: Rats. I'm going to have to get creative there, with some major surgery to move a  floppy over to my Windows machine.&lt;br /&gt;&lt;br /&gt;Anyway, I'm downloading Centos ISO's right now, so we'll see how they perform. Do you think that driver has to be specifically loaded before the install? I guess we'll find out ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114260681678520046?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114260681678520046/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114260681678520046' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114260681678520046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114260681678520046'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/03/poweredge-6400-great-os-debate_17.html' title='Poweredge 6400 -- the Great o/s Debate'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114260623806211962</id><published>2006-03-17T07:12:00.000-07:00</published><updated>2006-03-17T07:37:18.123-07:00</updated><title type='text'>Poweredge 6400 -- the Great o/s Debate</title><content type='html'>First, some boring details.&lt;br /&gt;&lt;br /&gt;The service tag for this machine is H6MGN01, and the recorded configuration seems to be pretty accurate. The critical part is this: "ASSEMBLY, CARD (CIRCUIT), POWEREDGE EXPANDABLE RAID CONTROLLER NUMBER, 3-DC, 128"&lt;br /&gt;&lt;br /&gt;Maybe it's a truism that the tricky part of working with these systems is getting the drivers for the array loaded before the install, but I seem to have worked that out. There was a nervous moment of array errors before I realized that the controller card was slightly unseated during shipping, but that seems to be a non-issue now.&lt;br /&gt;&lt;br /&gt;Dell appear to have pretty good support for Linux, on the whole. I've been through the information at http://linux.dell.com/storage.shtml and deduced the following.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The PERC 3/DC requires a MegaRAID driver "megaraid_mbox"&lt;/li&gt;&lt;li&gt;The required driver is present in RHEL4 kernel 2.6.9-5.EL and higher -- sounds good for a Whitbox or Centos install!&lt;/li&gt;&lt;li&gt;SLES9 ought to work, but has not been tested on the PERC3 series by Dell&lt;/li&gt;&lt;li&gt;The PERC3/DC firmware update must be extracted to floppy on a Windows machine&lt;/li&gt;&lt;li&gt;There are Solaris drivers for the Adaptec card, but not for the PERC3. Boooh.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Point 1: no problem. Actually SuSE 8 appears to have the right drivers also. I tried a quick install yesterday evening but it choked on reboot with a "GRUB loading stage2Read error" -- maybe something needs tweaking there.&lt;br /&gt;&lt;br /&gt;Point 3: Rats. I'm going to have to get creative there, with some major surgery to move a  floppy over to my Windows machine.&lt;br /&gt;&lt;br /&gt;Anyway, I'm downloading Centos ISO's right now, so we'll see how they perform. Do you think that driver has to be specifically loaded before the install? I guess we'll find out ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114260623806211962?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114260623806211962/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114260623806211962' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114260623806211962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114260623806211962'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/03/poweredge-6400-great-os-debate.html' title='Poweredge 6400 -- the Great o/s Debate'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114253859675164798</id><published>2006-03-16T12:43:00.000-07:00</published><updated>2006-03-16T12:49:56.806-07:00</updated><title type='text'>A New Arrival</title><content type='html'>My new (used) Poweredge 6400 arrived today -- a new dawn of technical complexity, electrical power consumption and noise pollution has arrived in the Sponge household.&lt;br /&gt;&lt;br /&gt;The first technical challenge is what name to give to the machine? In accordance with my own conventions it has to be that of a London train station, and because it is short, wide, and dressed in black I immediately thought it looks like a Victoria. Unfortunately I already have one of those, so I think it'll have to be "Waterloo".&lt;br /&gt;&lt;br /&gt;It'll be a fine chance to give a brief history lesson on the Empire's Days of Glory to my mob of ungrateful foreign colonial children.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114253859675164798?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114253859675164798/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114253859675164798' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114253859675164798'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114253859675164798'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/03/new-arrival.html' title='A New Arrival'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114245302234021125</id><published>2006-03-15T16:00:00.000-07:00</published><updated>2006-03-15T16:33:07.663-07:00</updated><title type='text'>Predicate Pushing And Analytic Functions</title><content type='html'>I'm sure that there must be a fair number of Oracle professionals who carry around in their heads a little score card of some of their best tuning results ever ... hopefully, at least, 'cos otherwise I'm a weirdo. Anyway, today I improved the performance of a set of decision support queries and achieved my best result ever - improving query speed by a factor of 180,000, from an original run time of one hour down to a new time of 0.02 seconds.&lt;br /&gt;&lt;br /&gt;The wise monkeys in the audience will immediately be thinking "partition pruning!" or "materialized view!", and in fact if you thought the former then you'd be right. Here's how it worked.&lt;br /&gt;&lt;br /&gt;I had defined a view against a large fact table so that it included several analytic functions. The details really don't matter, but the intention was to allow a column to contribute to a metric value only once per transaction_id, so the metric definition was something like:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Decode(Row_Number() Over (Partition By Transaction_ID Order By 1),1,Qty,0)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Queries that access this view had predicates on a number of columns, including some very selective indexed columns (Item_ID) and a partition key column (Fiscal_Month). Unfortunately there is nothing in the database to tell the optimizer that each unique value of Transaction_ID had but a single value Item_ID and Fiscal_Month, so logically the predicates could not be applied until after the analytic function had been calculated. Hence there was no predicate pushing on the fiscal_month and item_id, and neither partition pruning nor index access was considered. The query was actually scanning about one quarter of the table (it looks like a combination of subpartition pruning and partition pruning was taking place, but this table is multicolumn range + list composite partitioned, and pruning at the partition level was only taking place on the leading column of the partition key).&lt;br /&gt;&lt;br /&gt;However, we included the two predicate columns in the analytic functions' partition clause like so:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Decode(Row_Number() Over (Partition By Transaction_ID, Item_Id, Fiscal_Month Order By 1),1,Qty,0)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now this doesn't change the result because the Item_Id and Fiscal_Month entries are actually logically redundant, but it did allow both 9i and 10g to push the predicates and give full partition and subpartition pruning and index-based access.&lt;br /&gt;&lt;br /&gt;Quite a nice result.&lt;br /&gt;&lt;br /&gt;Here's a script that I used to demonstrate that it would work.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;drop table t1;&lt;br /&gt;create table t1&lt;br /&gt;   (&lt;br /&gt;   txid   ,&lt;br /&gt;   month  ,&lt;br /&gt;   item_cd,&lt;br /&gt;   qty  &lt;br /&gt;   )&lt;br /&gt;as&lt;br /&gt;select&lt;br /&gt;   floor(rownum/5),&lt;br /&gt;   floor(rownum/20),&lt;br /&gt;   floor(rownum/10),&lt;br /&gt;   floor(rownum/5)&lt;br /&gt;from&lt;br /&gt;   dual&lt;br /&gt;connect by&lt;br /&gt;   level &lt; 100&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;explain plan for&lt;br /&gt;select txid,&lt;br /&gt;       qty&lt;br /&gt;from   (&lt;br /&gt;       select txid,&lt;br /&gt;              item_cd,&lt;br /&gt;              month,&lt;br /&gt;              qty,&lt;br /&gt;              decode(row_number() &lt;br /&gt;              Over (Partition By txid Order By 1),1,qty,0)&lt;br /&gt;                 qty_fix&lt;br /&gt;       from   t1&lt;br /&gt;       ) v&lt;br /&gt;where  item_cd = 0&lt;br /&gt;/&lt;br /&gt;select * from table(dbms_xplan.display)&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;explain plan for&lt;br /&gt;select txid,&lt;br /&gt;       qty_fix&lt;br /&gt;from   (&lt;br /&gt;       select txid,&lt;br /&gt;              item_cd,&lt;br /&gt;              month,&lt;br /&gt;              qty,&lt;br /&gt;              decode(row_number()&lt;br /&gt;              Over (Partition By txid Order By 1),1,qty,0)&lt;br /&gt;                 qty_fix&lt;br /&gt;       from   t1&lt;br /&gt;       ) v&lt;br /&gt;where  item_cd = 0&lt;br /&gt;/&lt;br /&gt;select * from table(dbms_xplan.display)&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;explain plan for&lt;br /&gt;select txid,&lt;br /&gt;       qty_fix&lt;br /&gt;from   (&lt;br /&gt;       select txid,&lt;br /&gt;              item_cd,&lt;br /&gt;              month,&lt;br /&gt;              qty,&lt;br /&gt;              decode(row_number()&lt;br /&gt;              Over (Partition By txid,item_cd Order By 1),1,qty,0)&lt;br /&gt;                 qty_fix&lt;br /&gt;       from   t1&lt;br /&gt;       ) v&lt;br /&gt;where  item_cd = 0&lt;br /&gt;/&lt;br /&gt;select * from table(dbms_xplan.display)&lt;br /&gt;/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In 10g the explain plan with predicate pushing was very straightforward:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;PLAN_TABLE_OUTPUT&lt;br /&gt;--------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;Plan hash value: 2273146475&lt;br /&gt;&lt;br /&gt;----------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |&lt;br /&gt;----------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT    |      |     9 |   252 |     3  (34)| 00:00:01 |&lt;br /&gt;|   1 |  VIEW               |      |     9 |   252 |     3  (34)| 00:00:01 |&lt;br /&gt;|   2 |   WINDOW SORT       |      |     9 |   351 |     3  (34)| 00:00:01 |&lt;br /&gt;|*  3 |    TABLE ACCESS FULL| T1   |     9 |   351 |     2   (0)| 00:00:01 |&lt;br /&gt;----------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;PLAN_TABLE_OUTPUT&lt;br /&gt;--------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;Predicate Information (identified by operation id):&lt;br /&gt;---------------------------------------------------&lt;br /&gt;&lt;br /&gt;   3 - filter("ITEM_CD"=0)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Note the filter being applied to line 3. Where the predicate was not pushed it was applied to line 1.&lt;br /&gt;&lt;br /&gt;The 9i explain plan was rather ... funky. But it worked.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114245302234021125?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114245302234021125/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114245302234021125' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114245302234021125'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114245302234021125'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/03/predicate-pushing-and-analytic.html' title='Predicate Pushing And Analytic Functions'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114080081377066960</id><published>2006-02-24T09:44:00.000-07:00</published><updated>2006-02-24T10:06:53.836-07:00</updated><title type='text'>Creating Built-in Help For PL/SQL Packages</title><content type='html'>This is a trivial application of basic techniques, but it seemed to me to be an idea worthwhile of sharing.&lt;br /&gt;&lt;br /&gt;Anyway, I sometimes have a need to code up some PL/SQL to support ETL operations, and such procedures are often executed from the command line in SQL*Plus by operators. Currently I'm working on a generic package to support manual refresh of some troublesome materialized views.&lt;br /&gt;&lt;br /&gt;This is not necessarily the sort of thing that the operators will run every day, and hence it seems worthwhile to put the documentation for the procedures literally at their fingertips by providing a built-in help function. I've done this by adding to the package a definition of a pipelined function called HELP, which simply spools out descriptions of procedures and parameters, and here's how it works.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Start with an object type definition such as:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;create or replace TYPE HELP_TEXT_TYPE&lt;br /&gt;AS OBJECT ( help_text varchar2(80) );&lt;br /&gt;/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then add a table type definition:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;create or replace TYPE HELP_TEXT_TYPE_TABLE&lt;br /&gt;AS TABLE OF HELP_TEXT_TYPE;&lt;br /&gt;/&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In your package you'll need a pipelined function specification:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Create Package help_demo&lt;br /&gt;as&lt;br /&gt;   function help                     &lt;br /&gt;   return help_text_type_table&lt;br /&gt;   pipelined;&lt;br /&gt;End;&lt;br /&gt;/&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then the package body contains the function definition, such as:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Create or replace Package Body help_demo&lt;br /&gt;as&lt;br /&gt;   function help&lt;br /&gt;   return   help_text_type_table&lt;br /&gt;   pipelined&lt;br /&gt;   is&lt;br /&gt;   begin&lt;br /&gt;      Pipe Row(help_text_type('IF THIS IS DIFFICULT TO READ THEN USE THE COMMAND ...'));&lt;br /&gt;      Pipe Row(help_text_type('set heading off pagesize 1000'));&lt;br /&gt;      Pipe Row(help_text_type(''));&lt;br /&gt;      Pipe Row(help_text_type('HELP for package HELP_DEMO'));&lt;br /&gt;      Pipe Row(help_text_type('=========================='));&lt;br /&gt;      Pipe Row(help_text_type(''));&lt;br /&gt;      Pipe Row(help_text_type('Procedures'));&lt;br /&gt;      Pipe Row(help_text_type('----------'));&lt;br /&gt;      Pipe Row(help_text_type(''));&lt;br /&gt;      Pipe Row(help_text_type(' None'));&lt;br /&gt;      Pipe Row(help_text_type(''));&lt;br /&gt;      Pipe Row(help_text_type('Functions'));&lt;br /&gt;      Pipe Row(help_text_type('---------'));&lt;br /&gt;      Pipe Row(help_text_type(''));&lt;br /&gt;      Pipe Row(help_text_type('help:'));&lt;br /&gt;      Pipe Row(help_text_type(' You''re reading it now. This is a demonstration of how'));&lt;br /&gt;      Pipe Row(help_text_type(' to provide a built-in help functionality for a PL/SQL package'));&lt;br /&gt;      Pipe Row(help_text_type(' that is accessible through SQL*Plus to user of the package'));&lt;br /&gt;      Pipe Row(help_text_type(''));&lt;br /&gt;      Pipe Row(help_text_type('Parameters'));&lt;br /&gt;      Pipe Row(help_text_type('----------'));&lt;br /&gt;      Pipe Row(help_text_type(''));&lt;br /&gt;      Pipe Row(help_text_type(' There are none of those either, but if there were then they''d be'));&lt;br /&gt;      Pipe Row(help_text_type(' listed and described here, like the following examples'));&lt;br /&gt;      Pipe Row(help_text_type(''));&lt;br /&gt;      Pipe Row(help_text_type(' autocommit; (Y/N) Default N'));&lt;br /&gt;      Pipe Row(help_text_type('   Whether or not to commit each process as it completes'));&lt;br /&gt;      Pipe Row(help_text_type('   A commit will be issued at the end anyway'));&lt;br /&gt;      Pipe Row(help_text_type(''));&lt;br /&gt;      Pipe Row(help_text_type('That Is All'));&lt;br /&gt;      Pipe Row(help_text_type('==========='));&lt;br /&gt;      Pipe Row(help_text_type(''));&lt;br /&gt;      Pipe Row(help_text_type(' Get back to work'));&lt;br /&gt;   End;&lt;br /&gt;End;&lt;br /&gt;/&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;When you issue the query;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Select * from table(help_demo.help)&lt;br /&gt;/&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;... you get output such as ...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;IF THIS IS DIFFICULT TO READ THEN USE THE COMMAND ...&lt;br /&gt;set heading off pagesize 1000&lt;br /&gt;&lt;br /&gt;HELP for package HELP_DEMO&lt;br /&gt;==========================&lt;br /&gt;&lt;br /&gt;Procedures&lt;br /&gt;----------&lt;br /&gt;&lt;br /&gt; None&lt;br /&gt;&lt;br /&gt;Functions&lt;br /&gt;---------&lt;br /&gt;&lt;br /&gt;help:&lt;br /&gt; You're reading it now. This is a demonstration of how&lt;br /&gt; to provide a built-in help functionality for a PL/SQL package&lt;br /&gt; that is accessible through SQL*Plus to user of the package&lt;br /&gt;&lt;br /&gt;Parameters&lt;br /&gt;----------&lt;br /&gt;&lt;br /&gt; There are none of those either, but if there were then they'd be&lt;br /&gt; listed and described here, like the following examples&lt;br /&gt;&lt;br /&gt; autocommit; (Y/N) Default N&lt;br /&gt;   Whether or not to commit each process as it completes&lt;br /&gt;   A commit will be issued at the end anyway&lt;br /&gt;&lt;br /&gt;That Is All&lt;br /&gt;===========&lt;br /&gt;&lt;br /&gt; Get back to work&lt;br /&gt;&lt;br /&gt;33 rows selected.&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You might choose to wrap up the help functioanlity in a view, such as:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;create view help_demo&lt;br /&gt;as&lt;br /&gt;select * from table(help_demo.help)&lt;br /&gt;/&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;... to make is easier to access, or even use DBMS_OUTPUT to send the help text to the screen. I like this though as it's accessible directly through SQL, the Universal Language.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114080081377066960?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114080081377066960/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114080081377066960' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114080081377066960'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114080081377066960'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/02/creating-built-in-help-for-plsql.html' title='Creating Built-in Help For PL/SQL Packages'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-114055625582514254</id><published>2006-02-21T14:04:00.000-07:00</published><updated>2006-02-21T14:10:55.950-07:00</updated><title type='text'>Partition Change Tracking Fast Refresh Workaround?</title><content type='html'>I wrote a while ago that I didn't think that Partition Change Tracking (PCT) fast refresh was worth using, because eventually something will cause the refresh to fail and then, for various silly reasons, you can only get PCT FR back by completely rebuilding your MV in one shot. This is not a practical endeavour in many cases, hence PCT is not worth so much.&lt;br /&gt;&lt;br /&gt;However, it has now occured to me that if one kept a backup copy of the data in the PCT-based MV, even if it is only as a regular table, then in the event of disaster such a table could be brought up to dat with respect to the master tables(s) and with the correct MV definition placed over it temporarily the complete rebuild of the PCT-based MV could be rewritten to effectively be a full table scan of this backup. that ought to be more achievable I suppose.&lt;br /&gt;&lt;br /&gt;It still seems like a lot of trouble though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-114055625582514254?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/114055625582514254/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=114055625582514254' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114055625582514254'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/114055625582514254'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/02/partition-change-tracking-fast-refresh.html' title='Partition Change Tracking Fast Refresh Workaround?'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113816730686216260</id><published>2006-01-24T22:30:00.000-07:00</published><updated>2006-01-24T22:35:06.916-07:00</updated><title type='text'>Oracle Wiki at Dizwell</title><content type='html'>Howard's &lt;a href="http://dizwell.com/wiki/index.php"&gt;Wiki at Dizwell&lt;/a&gt; is up and running, and seems to be off to a very good start considering that this is a pretty new thing for many of us. I hope that everyone will be contributing -- these things only survive if we give it the oxygen of our participation, and I know that everyone has something to share.&lt;br /&gt;&lt;br /&gt;The text formatting takes a little getting used to but at the bottom of the edit pages there are brief tips that will get you through the experience pretty painlessly.&lt;br /&gt;&lt;br /&gt;Are you still here? Go, go ....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113816730686216260?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113816730686216260/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113816730686216260' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113816730686216260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113816730686216260'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/01/oracle-wiki-at-dizwell.html' title='Oracle Wiki at Dizwell'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113778966865155806</id><published>2006-01-20T13:40:00.000-07:00</published><updated>2006-01-20T13:41:08.690-07:00</updated><title type='text'>Communication Skills</title><content type='html'>Public speaking often being in part of the job, here's the help you may like.&lt;br /&gt;&lt;br /&gt;http://www.tmous.com/media/MOUS_falipornia.html&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113778966865155806?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113778966865155806/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113778966865155806' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113778966865155806'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113778966865155806'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/01/communication-skills.html' title='Communication Skills'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113778704098637019</id><published>2006-01-20T12:57:00.000-07:00</published><updated>2006-01-20T12:57:21.023-07:00</updated><title type='text'>Why We Fight</title><content type='html'>http://www.sonyclassics.com/whywefight/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113778704098637019?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113778704098637019/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113778704098637019' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113778704098637019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113778704098637019'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/01/why-we-fight.html' title='Why We Fight'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113756625823906036</id><published>2006-01-17T23:35:00.000-07:00</published><updated>2006-01-17T23:37:38.300-07:00</updated><title type='text'>An Odd Form Of Flattery</title><content type='html'>I think that if someone is going to &lt;a href="http://oralaks.blogspot.com/2005/12/art-of-writing-good-sql-by-david.html"&gt;copy your work&lt;/a&gt; to their own blog then the least they might do is provide a link to the original source ... oh wait, no the least they might do is spell your name right.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113756625823906036?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113756625823906036/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113756625823906036' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113756625823906036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113756625823906036'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/01/odd-form-of-flattery.html' title='An Odd Form Of Flattery'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113692145161282967</id><published>2006-01-10T12:22:00.000-07:00</published><updated>2006-01-10T12:30:51.660-07:00</updated><title type='text'>The Law Is An Ass</title><content type='html'>So it's now illegal to anonymously annoy someone on the internet. Sounds ridiculous, don't it?  Well, not according to the Violence Against Women and Department of Justice Reauthorization Act, which was cunningly attached to a must-pass funding bill for the Justice Department (a lovely example of the dysfunctionality of the US legislative system).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Read the whole stupid story &lt;a href="http://news.com.com/Create+an+e-annoyance,+go+to+jail/2010-1028_3-6022491.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;boy, I for one am glad that I never annoy people on the internet ... anonymously, that is.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113692145161282967?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113692145161282967/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113692145161282967' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113692145161282967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113692145161282967'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/01/law-is-ass.html' title='The Law Is An Ass'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113657094550624829</id><published>2006-01-06T10:58:00.000-07:00</published><updated>2006-01-06T11:09:05.553-07:00</updated><title type='text'>RMOUG Training Days 2006</title><content type='html'>The &lt;a href="http://www.rmoug.org/training.htm"&gt;RMOUG Training Days 2006&lt;/a&gt; are set for February 15-16 at the &lt;a href="http://www.denverconvention.com/"&gt;Colorado Convention Center&lt;/a&gt;. I always end up missing these events due to last minute emergencies, but this year I'm pretty determined to make it.&lt;br /&gt;&lt;br /&gt;Hey, if nothing else it'll be worth a few blog entries, and that's nothing to be sniffed at.&lt;br /&gt;&lt;br /&gt;Anyone planning on going?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113657094550624829?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113657094550624829/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113657094550624829' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113657094550624829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113657094550624829'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/01/rmoug-training-days-2006.html' title='RMOUG Training Days 2006'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113652888643354038</id><published>2006-01-05T22:52:00.000-07:00</published><updated>2006-01-05T23:28:06.486-07:00</updated><title type='text'>(Almost) Error Free Code</title><content type='html'>Picked up from Slashdot, an &lt;a href="http://www.spectrum.ieee.org/sep05/1454"&gt;article&lt;/a&gt; at IEEE about a British software house delivering code with less than one error per ten thousand &lt;a href="http://en.wikipedia.org/wiki/Source_lines_of_code"&gt;SLOC&lt;/a&gt;s, albeit at a premium of up to 50% higher costs than regular development. Their "secret" is to return to the roots of software engineering by describing the application in terms of a a formal specification language &lt;a href="http://en.wikipedia.org/wiki/Z_notation"&gt;Z&lt;/a&gt; ("zed") based on set theory and predicate logic before subjecting it to mathematical analysis to identify ambiguities and inconsistencies, and only then converting it to code (which itself becomes a relatively trivial task). Incidentally, they code in &lt;a href="http://en.wikipedia.org/wiki/SPARK_programming_language"&gt;Spark&lt;/a&gt;, a descendant of Ada, and if you follow that link to the Wikipedia article you'll see an example of some excellent commenting techniques under "Annotation Examples".&lt;br /&gt;&lt;br /&gt;Accurate and complete requirements gathering is emphasised, as is prototyping as a means of requirements feedback to the customer. In an example development described in the article the developed software showed just four faults in the first year of operation out of 100,000 SLOC.&lt;br /&gt;&lt;span class="" style="display: block;" id="formatbar_CreateLink" title="Link" onmouseover="ButtonHoverOn(this);" onmouseout="ButtonHoverOff(this);" onmouseup="" onmousedown="CheckFormatting(event);FormatbarButton('richeditorframe', this, 8);ButtonMouseDown(this);"&gt;&lt;/span&gt;&lt;span class="down" style="display: block;" id="formatbar_CreateLink" title="Link" onmouseover="ButtonHoverOn(this);" onmouseout="ButtonHoverOff(this);" onmouseup="" onmousedown="CheckFormatting(event);FormatbarButton('richeditorframe', this, 8);ButtonMouseDown(this);"&gt;&lt;/span&gt;&lt;br /&gt;I found the IEEE article rather inspiring, although at the end the comments on the willingness of programmers to use formal methods and logic are depressingly familiar.&lt;br /&gt;&lt;br /&gt;There are more details in a presentation by Praxis &lt;a href="http://www.stsc.hill.af.mil/crosstalk/2005/12/0512CroxfordChapman.html"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113652888643354038?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113652888643354038/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113652888643354038' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113652888643354038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113652888643354038'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2006/01/almost-error-free-code.html' title='(Almost) Error Free Code'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113570434567235892</id><published>2005-12-27T10:23:00.000-07:00</published><updated>2005-12-27T10:25:45.710-07:00</updated><title type='text'>"The Economist" Premium Content Free</title><content type='html'>OK, you have to watch a short commercial, but that's capitalism folks. And it's a small price of entry for the world's best world affairs and business coverage.&lt;br /&gt;&lt;br /&gt;http://www.economist.com&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113570434567235892?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113570434567235892/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113570434567235892' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113570434567235892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113570434567235892'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/economist-premium-content-free.html' title='&quot;The Economist&quot; Premium Content Free'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113509751440454562</id><published>2005-12-20T09:44:00.000-07:00</published><updated>2005-12-20T09:51:54.473-07:00</updated><title type='text'>The Tranquility of Materialized Views</title><content type='html'>Yesterday evening I searched the Oracle 10g documentation for the string "materialized views", and was browsing through the 378 matching entries in "Error Messages". At about the point where I got to &lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10744/e9858.htm#ORA-12055"&gt;ORA-12055: materialized view definition contains cyclic dependencies with existing materialized views&lt;/a&gt; I was overcome with a great sense of tranquility and understanding of materialized views.&lt;br /&gt;&lt;br /&gt;Shortly after that I realised that I was probably delusional from lack of sleep or something, so I snapped out of it and went to bed. Is it still only Tuesday today?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113509751440454562?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113509751440454562/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113509751440454562' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113509751440454562'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113509751440454562'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/tranquility-of-materialized-views.html' title='The Tranquility of Materialized Views'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113486323935607647</id><published>2005-12-17T16:39:00.000-07:00</published><updated>2005-12-17T16:52:04.400-07:00</updated><title type='text'>Optimizing Materialized Views Part V: HOLAP Query Performance</title><content type='html'>&lt;p&gt;&lt;i&gt;&lt;b&gt;HOLAP Performance With Different Aggregation Levels&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;  &lt;p&gt;I'm going to construct a slightly different test data set for this experiment, involving the aggregation of 10,000,000 by three different columns each having around 1000 distinct values.&lt;/p&gt;  &lt;pre&gt;drop table master;&lt;br /&gt;&lt;br /&gt;create table master&lt;br /&gt;  (&lt;br /&gt;  col1    not null,&lt;br /&gt;  col2    not null,&lt;br /&gt;  col3    not null,&lt;br /&gt;  tx_qty  not null&lt;br /&gt;  )&lt;br /&gt;pctfree 0&lt;br /&gt;nologging&lt;br /&gt;as&lt;br /&gt;select&lt;br /&gt;  trunc(dbms_random.value(1,1000)),&lt;br /&gt;  trunc(dbms_random.value(1,1000)),&lt;br /&gt;  trunc(dbms_random.value(1,1000)),&lt;br /&gt;  trunc(dbms_random.value(1,100),2)&lt;br /&gt;from&lt;br /&gt;  dual&lt;br /&gt;connect by&lt;br /&gt;  1=1 and&lt;br /&gt;   level &lt;= 1000000;&lt;/pre&gt;&lt;br /&gt; &lt;p&gt; The performance test queries will take the form of a query such as the following:&lt;/p&gt;  &lt;pre&gt;clear screen&lt;br /&gt;alter session set workarea_size_policy = manual;&lt;br /&gt;alter session set sort_area_size = 1000000000;&lt;br /&gt;alter session set sort_area_retained_size = 1000000;&lt;br /&gt;set timing on autotrace on feedback off&lt;br /&gt;&lt;br /&gt;-- loop: the following executed four times&lt;br /&gt;alter system flush buffer_cache;&lt;br /&gt;select sum(s_tx_qty) from&lt;br /&gt;(Select&lt;br /&gt;  sum(tx_qty) s_tx_qty,&lt;br /&gt;  {grouped column list}&lt;br /&gt;From master group by grouping sets&lt;br /&gt;  ({grouping sets});&lt;br /&gt;-- end of loop&lt;/pre&gt; &lt;p&gt; In the four executions of the query the first invokes a hard parse and the autotrace statistics are discarded. The autotrace results of the following three results are averaged.&lt;/p&gt;  &lt;p&gt;We will try aggregations at a number of different levels. Some of these will involve hierarchies and some will not, but the aim is to expose as full a range of optimizations as we can. For the sake of my time, my sanity, and blog length I'm going to run these to get simple wall clock times and autotrace statistics for now. The host machine and database will be as quiescent as possible.&lt;/p&gt;  &lt;p&gt;We'll start with simple, conventional aggregations to get benchmarks for familiar operations.&lt;/p&gt;  &lt;table border="1" cellpadding="4" cellspacing="3" width="596"&gt;   &lt;col width="107"&gt;  &lt;col width="108"&gt;  &lt;col width="108"&gt;  &lt;col width="108"&gt;  &lt;col width="104"&gt;  &lt;thead&gt;   &lt;tr valign="top"&gt;    &lt;th width="107"&gt;     &lt;p&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/th&gt;    &lt;th width="108"&gt;     &lt;p&gt;Benchmark 1&lt;/p&gt;    &lt;/th&gt;    &lt;th width="108"&gt;     &lt;p&gt;Benchmark 2&lt;/p&gt;    &lt;/th&gt;    &lt;th width="108"&gt;     &lt;p&gt;Benchmark 3&lt;/p&gt;    &lt;/th&gt;    &lt;th width="104"&gt;     &lt;p&gt;Benchmark 4&lt;/p&gt;    &lt;/th&gt;   &lt;/tr&gt;  &lt;/thead&gt;  &lt;tbody&gt;   &lt;tr valign="top"&gt;    &lt;td width="107"&gt;     &lt;p&gt;&lt;b&gt;Group By&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p align="center"&gt;&lt;b&gt;None&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p align="center"&gt;&lt;b&gt;col1&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p align="center"&gt;&lt;b&gt;col1,col2&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="104"&gt;     &lt;p align="center"&gt;&lt;b&gt;Col, col2, col3&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="107"&gt;     &lt;p&gt;&lt;b&gt;rows&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p&gt;1&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p&gt;999&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p&gt;997,955&lt;/p&gt;    &lt;/td&gt;    &lt;td width="104"&gt;     &lt;p&gt;9,949,574&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="107"&gt;     &lt;p&gt;&lt;b&gt;consistent gets&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p&gt;25,074&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p&gt;25,074&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p&gt;25,074&lt;/p&gt;    &lt;/td&gt;    &lt;td width="104"&gt;     &lt;p&gt;25,074&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="107"&gt;     &lt;p&gt;&lt;b&gt;physical reads&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p&gt;25,062&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p&gt;25,062&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p&gt;25,062&lt;/p&gt;    &lt;/td&gt;    &lt;td width="104"&gt;     &lt;p&gt;25,062&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="107"&gt;     &lt;p&gt;&lt;b&gt;sorts (memory)&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p&gt;1&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p&gt;1&lt;/p&gt;    &lt;/td&gt;    &lt;td width="104"&gt;     &lt;p&gt;1&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="107"&gt;     &lt;p&gt;&lt;b&gt;Elapsed Time&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p&gt;8.87&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p&gt;18.95&lt;/p&gt;    &lt;/td&gt;    &lt;td width="108"&gt;     &lt;p&gt;59.70&lt;/p&gt;    &lt;/td&gt;    &lt;td width="104"&gt;     &lt;p&gt;92.42&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;  &lt;/tbody&gt; &lt;/table&gt;  &lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p&gt;In the following table we present the results of the various grouping set tests, with the “Y” indicating that the grouping set was included as part of that test.&lt;/p&gt;  &lt;table border="1" cellpadding="4" cellspacing="3" width="662"&gt;   &lt;col width="140"&gt;  &lt;col width="42"&gt;  &lt;col width="42"&gt;  &lt;col width="40"&gt;  &lt;col width="42"&gt;  &lt;col width="50"&gt;  &lt;col width="62"&gt;  &lt;col width="70"&gt;  &lt;col width="66"&gt;  &lt;thead&gt;   &lt;tr valign="top"&gt;    &lt;th width="140"&gt;     &lt;p&gt;Grouping Set(s) Used&lt;/p&gt;    &lt;/th&gt;    &lt;th width="42"&gt;     &lt;p&gt;Test 1&lt;/p&gt;    &lt;/th&gt;    &lt;th width="42"&gt;     &lt;p&gt;Test 2&lt;/p&gt;    &lt;/th&gt;    &lt;th width="40"&gt;     &lt;p&gt;Test 3&lt;/p&gt;    &lt;/th&gt;    &lt;th width="42"&gt;     &lt;p&gt;Test 4&lt;/p&gt;    &lt;/th&gt;    &lt;th width="50"&gt;     &lt;p&gt;Test 5&lt;/p&gt;    &lt;/th&gt;    &lt;th width="62"&gt;     &lt;p&gt;Test 6&lt;/p&gt;    &lt;/th&gt;    &lt;th width="70"&gt;     &lt;p&gt;Test 7&lt;/p&gt;    &lt;/th&gt;    &lt;th width="66"&gt;     &lt;p&gt;Test 8&lt;/p&gt;    &lt;/th&gt;   &lt;/tr&gt;  &lt;/thead&gt;  &lt;tbody&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;()&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;(COL1)&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;(COL2)&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;(COL3)&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;(COL1,COL2)&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;(COL1,COL3)&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;(COL2,COL3)&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;(COL1,COL2,COL3)&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="center"&gt;&lt;br /&gt;    &lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="center"&gt;&lt;b&gt;Y&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;rows&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;1&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;999&lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="right"&gt;1,000&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;1,999&lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="right"&gt;999,954&lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="right"&gt;2,996,849&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="right"&gt;10,948,529&lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="right"&gt;12,946,423&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;recursive calls&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;185&lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="right"&gt;25&lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="right"&gt;299&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="right"&gt;270      &lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="right"&gt;319&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;db block gets&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;23,575&lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="right"&gt;2803&lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="right"&gt;38,219&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="right"&gt;34745      &lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="right"&gt;40,872&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;consistent gets&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;25,074&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;25,074&lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="right"&gt;25074&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;71,498&lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="right"&gt;33286&lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="right"&gt;122,911&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="right"&gt;62313&lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="right"&gt;130,765&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;physical reads&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;25,062&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;25,062&lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="right"&gt;25062&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;71,434&lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="right"&gt;27799      &lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="right"&gt;122,776&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="right"&gt;62242&lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="right"&gt;130,622&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;redo size&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;1,929&lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="right"&gt;2,147&lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="right"&gt;3525.33&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="right"&gt;1513&lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="right"&gt;3,080&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;sorts (memory)&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;1&lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="right"&gt;1&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;2&lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="right"&gt;3      &lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="right"&gt;4&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="right"&gt;2&lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="right"&gt;4&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;sorts (disk)&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="right"&gt;0&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;   &lt;tr valign="top"&gt;    &lt;td width="140"&gt;     &lt;p&gt;&lt;b&gt;Elapsed Time&lt;/b&gt;&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;12.33&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;16.34&lt;/p&gt;    &lt;/td&gt;    &lt;td width="40"&gt;     &lt;p align="right"&gt;17.84&lt;/p&gt;    &lt;/td&gt;    &lt;td width="42"&gt;     &lt;p align="right"&gt;63.57&lt;/p&gt;    &lt;/td&gt;    &lt;td width="50"&gt;     &lt;p align="right"&gt;71.49&lt;/p&gt;    &lt;/td&gt;    &lt;td width="62"&gt;     &lt;p align="right"&gt;230.23&lt;/p&gt;    &lt;/td&gt;    &lt;td width="70"&gt;     &lt;p align="right"&gt;173.08&lt;/p&gt;    &lt;/td&gt;    &lt;td width="66"&gt;     &lt;p align="right"&gt;266.69&lt;/p&gt;    &lt;/td&gt;   &lt;/tr&gt;  &lt;/tbody&gt; &lt;/table&gt;  &lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p&gt;&lt;b&gt;&lt;i&gt;Test 1&lt;/i&gt;&lt;/b&gt; is a straight aggregation to find the sum of tx_qty, but expressed as a grouping set of () rather than the usual “Select Sum(my_col) From my_table” syntax. The autotrace statistics are also very conventional and show physical reads very close to consistent gets, with no db block gets or recursive SQL.&lt;/p&gt;  &lt;p&gt;This test is logically the same as Benchmark 1, but required an elapsed time 50% longer. The execution plans are in fact different, with the SORT AGGREGATE of the conventional method being replaced with a SORT GROUP BY NOSORT in the grouping sets method.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;&lt;i&gt;Test 2&lt;/i&gt;&lt;/b&gt; is similarly conventional, finding the sum of tx_qty grouped by col1. Again this is expressed as a grouping set (col1) rather than the regular syntax and the autotrace statistics are very similar to Test 1 with the addition of an in-memory sort. The performance is very similar to that of Benchmark 2, to which it is logically equivalent, and both queries are using a SORT GROUP BY operation.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;&lt;i&gt;Test 3&lt;/i&gt;&lt;/b&gt; gives our first hierarchical result set, combining the results of Test 1 and Test 2. In fact the result set for Test 3 is logically equivalent to (Benchmark1 UNION ALL Benchmark 2), and the benefits of the HOLAP cube begin to show themselves. The average elapsed time of 17.84 seconds is only 62% of the elapsed times for Tests 1 and 2 combined. The execution plan shows a SORT (GROUP BY ROLLUP) operation which is evidently an optimization specifically for hierarchical cube queries. It appears either that the result for the (COL1) grouping set is being used as the basis for the () grouping set calculation, or that the results for both sets are being computed in the same operation. As we will shortly see, the latter appears to be the more probable scenario.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;&lt;i&gt;Test 4&lt;/i&gt;&lt;/b&gt; adds into Test 3 a grouping set of (Col2), giving two sets at the same level with no more detailed level included. This result ought to be logically similar to (Test 2 UNION ALL Test 3) -- with the appropriate columns being used -- or (Benchmark 1 UNION ALL Benchmark 2 UNION ALL Benchmark 3). The result is surprising because this time the performance is well in excess of those comparisons, and gives the first hint at a possible contra-indication for HOLAP cube MV's. The elapsed time of 63.57 seconds is 86% higher than the sum of the elapsed times for Tests 2 and 3, of 34.18 seconds.&lt;/p&gt;  &lt;p&gt;The explain plan show the creation of two temporary tables, although when the statement is executed these temporary table names are of course different.&lt;/p&gt;  &lt;pre&gt;------------------------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation                    | Name                        | Rows  | Bytes | Cost (%CPU)| Time     |&lt;br /&gt;------------------------------------------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT             |                             |     1 |       |   170  (85)| 00:00:02 |&lt;br /&gt;|   1 |  SORT AGGREGATE              |                             |     1 |       |            |          |&lt;br /&gt;|   2 |   VIEW                       |                             |   707K|       |   170  (85)| 00:00:02 |&lt;br /&gt;|   3 |    TEMP TABLE TRANSFORMATION |                             |       |       |            |          |&lt;br /&gt;|   4 |     LOAD AS SELECT           |                             |       |       |            |          |&lt;br /&gt;|   5 |      TABLE ACCESS FULL       | MASTER                      |    10M|   114M|   162  (88)| 00:00:02 |&lt;br /&gt;|   6 |     LOAD AS SELECT           |                             |       |       |            |          |&lt;br /&gt;|   7 |      SORT GROUP BY           |                             |     1 |    26 |     3  (34)| 00:00:01 |&lt;br /&gt;|   8 |       TABLE ACCESS FULL      | SYS_TEMP_0FD9D6665_1214756C |     1 |    26 |     2   (0)| 00:00:01 |&lt;br /&gt;|   9 |     LOAD AS SELECT           |                             |       |       |            |          |&lt;br /&gt;|  10 |      SORT GROUP BY ROLLUP    |                             |     1 |    26 |     3  (34)| 00:00:01 |&lt;br /&gt;|  11 |       TABLE ACCESS FULL      | SYS_TEMP_0FD9D6665_1214756C |     1 |    26 |     2   (0)| 00:00:01 |&lt;br /&gt;|  12 |     VIEW                     |                             |     1 |    39 |     2   (0)| 00:00:01 |&lt;br /&gt;|  13 |      TABLE ACCESS FULL       | SYS_TEMP_0FD9D6666_1214756C |     1 |    39 |     2   (0)| 00:00:01 | ------------------------------------------------------------------------------------------------------------&lt;/pre&gt; &lt;p&gt; Here are the STAT lines from a 10046 trace file:&lt;/p&gt;  &lt;pre&gt;STAT #6 id=1 cnt=1999 pid=0 pos=1 obj=0 op='TEMP TABLE TRANSFORMATION  (cr=71632 pr=66687 pw=23191 time=58587487 us)'&lt;br /&gt;STAT #6 id=10 cnt=1999 pid=1 pos=1 obj=0 op='VIEW  (cr=144 pr=6 pw=0 time=27785 us)'&lt;br /&gt;STAT #6 id=11 cnt=1999 pid=10 pos=1 obj=-40016278 op='TABLE ACCESS FULL SYS_TEMP_4254951018 (cr=144 pr=6 pw=0 time=19771 us)'&lt;br /&gt;STAT #6 id=12 cnt=1 pid=1 pos=2 obj=0 op='LOAD AS SELECT  (cr=25074 pr=20328 pw=23185 time=19896368 us)'&lt;br /&gt;STAT #6 id=13 cnt=10000000 pid=2 pos=1 obj=260950 op='TABLE ACCESS FULL OBJ#(260950) (cr=25074 pr=20328 pw=0 time=30000104 us)'&lt;br /&gt;STAT #6 id=14 cnt=1 pid=1 pos=3 obj=0 op='LOAD AS SELECT  (cr=23208 pr=23185 pw=3 time=18510637 us)'&lt;br /&gt;STAT #6 id=15 cnt=999 pid=4 pos=1 obj=0 op='SORT GROUP BY (cr=23208 pr=23185 pw=0 time=18508219 us)'&lt;br /&gt;STAT #6 id=16 cnt=10000000 pid=5 pos=1 obj=-40016279 op='TABLE ACCESS FULL SYS_TEMP_4254951017 (cr=23208 pr=23185 pw=0 time=30022328 us)'&lt;br /&gt;STAT #6 id=17 cnt=1 pid=1 pos=4 obj=0 op='LOAD AS SELECT  (cr=23206 pr=23168 pw=3 time=20142290 us)'&lt;br /&gt;STAT #6 id=18 cnt=1000 pid=7 pos=1 obj=0 op='SORT GROUP BY ROLLUP (cr=23206 pr=23168 pw=0 time=20140880 us)'&lt;br /&gt;STAT #6 id=19 cnt=10000000 pid=8 pos=1 obj=-40016279 op='TABLE ACCESS FULL SYS_TEMP_4254951017 (cr=23206 pr=23168 pw=0 time=30018947 us)'&lt;/pre&gt; &lt;p&gt; Cleaned up a little, this reads more easily as:&lt;/p&gt;  &lt;pre&gt;TEMP TABLE TRANSFORMATION&lt;br /&gt;VIEW&lt;br /&gt; TABLE ACCESS FULL SYS_TEMP_4254951018&lt;br /&gt;LOAD AS SELECT&lt;br /&gt; TABLE ACCESS FULL OBJ#(260950)&lt;br /&gt;LOAD AS SELECT&lt;br /&gt; SORT GROUP BY&lt;br /&gt;  TABLE ACCESS FULL SYS_TEMP_4254951017&lt;br /&gt;LOAD AS SELECT&lt;br /&gt; SORT GROUP BY ROLLUP&lt;br /&gt;  TABLE ACCESS FULL SYS_TEMP_4254951017&lt;/pre&gt; &lt;p&gt; The temporary table definitions are as follows:&lt;/p&gt;  &lt;pre&gt;CREATE GLOBAL TEMPORARY TABLE "SYS"."SYS_TEMP_0FD9D6669_1214756C"&lt;br /&gt;  ("C0" NUMBER,&lt;br /&gt;   "C1" NUMBER,&lt;br /&gt;   "A0" NUMBER )&lt;br /&gt;IN_MEMORY_METADATA CURSOR_SPECIFIC_SEGMENT STORAGE (OBJNO 4254951017 ) NOPARALLEL;&lt;br /&gt;&lt;br /&gt;CREATE GLOBAL TEMPORARY TABLE "SYS"."SYS_TEMP_0FD9D666A_1214756C"&lt;br /&gt;  ("C0" NUMBER,&lt;br /&gt;   "C1" NUMBER,&lt;br /&gt;   "D0" NUMBER,&lt;br /&gt;   "A0" NUMBER )&lt;br /&gt;IN_MEMORY_METADATA CURSOR_SPECIFIC_SEGMENT STORAGE (OBJNO 4254951018 ) NOPARALLEL&lt;/pre&gt; &lt;p&gt; You'll note that the global temporary tables' OBJNO clause correlate to part of the temporary table name referenced in the STAT lines – a bit unintuitive that, if you ask me.&lt;/p&gt;  &lt;p&gt;So how do we interpret this? Fortunately, a 10046 trace file contains some interesting clues.&lt;/p&gt;  &lt;p&gt;Although it shows the creation of the temporary tables it does not reveal any other recursive SQL against them. However it does show wait events of course, and where there is a 'db file scattered read' there are also p1 and p2 parameters which tell you the file number and block number respectively for the object being read. Now the only objects involved here ought to be our MASTER table and our two temporary tables, and we know the file and block numbers for the MASTER table are available from DBA_EXTENTS.&lt;/p&gt;  &lt;p&gt;So I'm going to break off there for this entry, and present the analysis of the execution plan, and more, next time.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113486323935607647?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113486323935607647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113486323935607647' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113486323935607647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113486323935607647'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/optimizing-materialized-views-part-v.html' title='Optimizing Materialized Views Part V: HOLAP Query Performance'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113466775811843695</id><published>2005-12-15T10:12:00.000-07:00</published><updated>2005-12-15T10:29:18.166-07:00</updated><title type='text'>An International Community, Apparantly</title><content type='html'>I recently increased my StatCounter log size to 1,000 -- more from boredom than any real need, admittedly -- and have found it fascinating to see the range of countries that the Sponge gets visits from. Here is my current list:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Country                   Visits&lt;br /&gt;===============           ======&lt;br /&gt;United States:            209&lt;br /&gt;United Kingdom:           72&lt;br /&gt;Australia:                26&lt;br /&gt;Switzerland:              21&lt;br /&gt;Canada:                   20&lt;br /&gt;Sweden:                   12&lt;br /&gt;Unknown:                  12&lt;br /&gt;India:                    11&lt;br /&gt;Greece:                   9&lt;br /&gt;Germany:                  9&lt;br /&gt;Netherlands:              6&lt;br /&gt;Turkey:                   6&lt;br /&gt;Luxembourg:               5&lt;br /&gt;Singapore:                5&lt;br /&gt;Slovenia:                 4&lt;br /&gt;France:                   4&lt;br /&gt;Denmark:                  4&lt;br /&gt;Spain:                    4&lt;br /&gt;Estonia:                  3&lt;br /&gt;Hong Kong:                2&lt;br /&gt;Romania:                  2&lt;br /&gt;Belgium:                  2&lt;br /&gt;Ukraine:                  2&lt;br /&gt;Serbia And Montenegro:    1&lt;br /&gt;Saudi Arabia:             1&lt;br /&gt;Egypt:                    1&lt;br /&gt;Lebanon:                  1&lt;br /&gt;Japan:                    1&lt;br /&gt;Czech Republic:           1&lt;br /&gt;Lithuania:                1&lt;br /&gt;Austria:                  1&lt;br /&gt;Finland                   1&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you see, Septics lead the way, followed closely by other English speaking countries.&lt;br /&gt;&lt;br /&gt;Being the well-travelled International Citizen that I am, I'm a little embarrassed that I sometimes get goggly at the thought of all these far-away places, and also that I use non-words like "goggly" and "septic" to an international audience. I catch myself thinking dumb things like, "Wow! They have databases in Lithuania!?!?". Yes dumbass, they also have cars and washing machines as well, I expect.&lt;br /&gt;&lt;br /&gt;Anyway, a question: what do people use for support in the smaller countries of the world? Do Oracle have national support staff speaking the local language(s), or do you rely on a regional system where the major regional languages are spoken, or do you have to fall back on knowledge of English and contact Oracle's global support people? I was trying to find out a while back whether Oracle published their documentation in any languages other than English, but pretty much drew a blank on it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113466775811843695?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113466775811843695/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113466775811843695' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113466775811843695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113466775811843695'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/international-community-apparantly.html' title='An International Community, Apparantly'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113454040687946197</id><published>2005-12-13T22:34:00.000-07:00</published><updated>2005-12-14T11:33:10.340-07:00</updated><title type='text'>Reunited With Old Technology</title><content type='html'>While standing on a chair in my basement storage room to make tweaks to my Shelf Of Technology, I was distracted by an aluminium case that I'd been carrying from abode to abode for about fifteen years without opening it as far as I could recall. Nestled snugly inside the blue foam padding within was my first proper camera, a Pentax ME Super.&lt;br /&gt;&lt;br /&gt;It's been a while since I've handled it, and it felt heavy, solid, and just a delight to hold. After fifteen years, did it still work?&lt;br /&gt;&lt;br /&gt;Away to a local store for a pair of LR44 batteries and the smallest roll of film available. Straightaway more memories came back. The batteries go in "+" side down, and they always try and flip themselves over. The little white button that has to be pressed to change the shutter action is fiddly. Little LEDs in the view finder tell you the shutter speed it will choose on the Auto setting. And it still feels heavy, especially after a few years with my Sony Cybershot digital.&lt;br /&gt;&lt;br /&gt;The first roll of file flew by. It was really too dark for an ISO100 so I had to find kids at their most stationary, which any parent can tell you means that they were just sitting mostly still but vibrating slightly with surplus energy -- on average, they were not moving. The light was artificial so it had a warm cast to it that the flash on the digital camera would have obscured.&lt;br /&gt;&lt;br /&gt;So here's the results so far.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://slimdave.smugmug.com/photos/48248602-O-0.jpg"&gt;&lt;img style="cursor: pointer; width: 320px;" src="http://slimdave.smugmug.com/photos/48248602-M-0.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://slimdave.smugmug.com/photos/48248603-M-0.jpg"&gt;&lt;img style="cursor: pointer; width: 320px;" src="http://slimdave.smugmug.com/photos/48248603-M-0.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://slimdave.smugmug.com/photos/48248605-M-0.jpg"&gt;&lt;img style="cursor: pointer; width: 320px;" src="http://slimdave.smugmug.com/photos/48248605-M-0.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://slimdave.smugmug.com/photos/48248606-M-0.jpg"&gt;&lt;img style="cursor: pointer; width: 320px;" src="http://slimdave.smugmug.com/photos/48248606-M-0.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://SlimDave.smugmug.com/photos/48296884-O-0.jpg"&gt;&lt;img style="cursor: pointer; width: 320px;" src="http://SlimDave.smugmug.com/photos/48296884-M-0.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The photo CD does not give great resolution and the 35mm aspect ratio is a little different, but so far it's encouraging enough for an investment in three rolls of faster black and white film. Some of the reviews I've read of this model mention its strength with black and white in particular, so now I need a chance to get up into the mountains to try it out so my creative urges have outlets other than endless images of the cat, the kids and the strata of detritus on my desk.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113454040687946197?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113454040687946197/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113454040687946197' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113454040687946197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113454040687946197'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/reunited-with-old-technology.html' title='Reunited With Old Technology'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113450038219629225</id><published>2005-12-13T11:24:00.000-07:00</published><updated>2005-12-14T10:08:34.283-07:00</updated><title type='text'>Playing With System Statistics</title><content type='html'>&lt;span style="font-style: italic; color: rgb(255, 0, 0);"&gt;Updated 14-Dec-2005 at the end of the article&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I was just musing on what we can deduce directly from system statistics, and thought of the following.&lt;br /&gt;&lt;br /&gt;If the system recorded the average MBRC and the average MREADTIM over the period of statistics collection, then does that mean that we can learn something directly about the performance of the i/o system during that time? I ran an experiment:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;drop table t&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;create table t&lt;br /&gt; nologging&lt;br /&gt; pctfree 99&lt;br /&gt; pctused 0&lt;br /&gt; tablespace REG_UA4MB_MSSM&lt;br /&gt;as&lt;br /&gt;select rpad(rownum,100) whatever&lt;br /&gt;from   dual&lt;br /&gt;connect by 1=1 and&lt;br /&gt;     level &lt; estimate_percent=""&gt; 1,block_sample =&gt; true)&lt;br /&gt;&lt;br /&gt;select blocks*&lt;br /&gt;     (select block_size&lt;br /&gt;      from   user_tablespaces&lt;br /&gt;      where  tablespace_name = 'REG_UA4MB_MSSM')&lt;br /&gt;     /1024/1024 table_size_Mb&lt;br /&gt;from   user_tables&lt;br /&gt;where table_name = 'T'&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;alter  system flush buffer_cache;&lt;br /&gt;&lt;br /&gt;exec   dbms_stats.gather_system_stats('START')&lt;br /&gt;&lt;br /&gt;select count(*) from t;&lt;br /&gt;&lt;br /&gt;exec   dbms_stats.gather_system_stats('STOP')&lt;br /&gt;&lt;br /&gt;select pname,&lt;br /&gt;     pval1&lt;br /&gt;from   sys.aux_stats$&lt;br /&gt;where  sname = 'SYSSTATS_MAIN'&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;select (select pval1&lt;br /&gt;      from   sys.aux_stats$&lt;br /&gt;      where  sname = 'SYSSTATS_MAIN' and&lt;br /&gt;             pname = 'MBRC') *&lt;br /&gt;     (select to_number(value) block_size&lt;br /&gt;      from   v$parameter&lt;br /&gt;      where  name = 'db_block_size') /&lt;br /&gt;     (select pval1&lt;br /&gt;      from   sys.aux_stats$&lt;br /&gt;      where  sname = 'SYSSTATS_MAIN' and&lt;br /&gt;             pname = 'MREADTIM')&lt;br /&gt;     /1024 sys_stat_mread_speed&lt;br /&gt;from dual&lt;br /&gt;/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What I'm doing there is creating a table of around 512Mb (because I'm aiming for one row per block, and each block is 8kb), flushing the buffer cache, starting the collection of system statistics, timing a select of count(*) for the 512Mb table, and comparing the read speed according to table_size/duration against MBRC*block_size/MREADTIM.&lt;br /&gt;&lt;br /&gt;In fact the correlation is pretty good. Here's my own execution of the above script with timing on:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SQL&gt; drop table t&lt;br /&gt;2  /&lt;br /&gt;&lt;br /&gt;Table dropped.&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:00.37&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; create table t&lt;br /&gt;2     nologging&lt;br /&gt;3     pctfree 99&lt;br /&gt;4     pctused 0&lt;br /&gt;5     tablespace REG_UA4MB_MSSM&lt;br /&gt;6  as&lt;br /&gt;7  select rpad(rownum,100) whatever&lt;br /&gt;8  from   dual&lt;br /&gt;9  connect by 1=1 and&lt;br /&gt;10         level &lt;&gt;&lt;br /&gt;SQL&gt; exec dbms_stats.gather_table_stats(user,'T',estimate_percent=&gt; 1,block_samp&lt;br /&gt;le =&gt; true)&lt;br /&gt;&lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:04.29&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select blocks*&lt;br /&gt;2         (select block_size&lt;br /&gt;3          from   user_tablespaces&lt;br /&gt;4          where  tablespace_name = 'REG_UA4MB_MSSM')&lt;br /&gt;5         /1024/1024 table_size_Mb&lt;br /&gt;6  from   user_tables&lt;br /&gt;7  where table_name = 'T'&lt;br /&gt;8  /&lt;br /&gt;&lt;br /&gt;TABLE_SIZE_MB&lt;br /&gt;-------------&lt;br /&gt; 511.992188&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:00.06&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; alter  system flush buffer_cache;&lt;br /&gt;&lt;br /&gt;System altered.&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:00.01&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; exec   dbms_stats.gather_system_stats('START')&lt;br /&gt;&lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:00.28&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select count(*) from t;&lt;br /&gt;&lt;br /&gt;COUNT(*)&lt;br /&gt;----------&lt;br /&gt;   65535&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:13.12&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; exec   dbms_stats.gather_system_stats('STOP')&lt;br /&gt;&lt;br /&gt;PL/SQL procedure successfully completed.&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:00.04&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select pname,&lt;br /&gt;2         pval1&lt;br /&gt;3  from   sys.aux_stats$&lt;br /&gt;4  where  sname = 'SYSSTATS_MAIN'&lt;br /&gt;5  /&lt;br /&gt;&lt;br /&gt;PNAME                               PVAL1&lt;br /&gt;------------------------------ ----------&lt;br /&gt;CPUSPEEDNW                       1132.397&lt;br /&gt;IOSEEKTIM                              10&lt;br /&gt;IOTFRSPEED                           4096&lt;br /&gt;SREADTIM                           11.039&lt;br /&gt;MREADTIM                           11.886&lt;br /&gt;CPUSPEED                             1084&lt;br /&gt;MBRC                                   63&lt;br /&gt;MAXTHR                           36093952&lt;br /&gt;SLAVETHR                          2065408&lt;br /&gt;&lt;br /&gt;9 rows selected.&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:00.00&lt;br /&gt;SQL&gt;&lt;br /&gt;SQL&gt; select (select pval1&lt;br /&gt;2          from   sys.aux_stats$&lt;br /&gt;3          where  sname = 'SYSSTATS_MAIN' and&lt;br /&gt;4                 pname = 'MBRC') *&lt;br /&gt;5         (select to_number(value) block_size&lt;br /&gt;6          from   v$parameter&lt;br /&gt;7          where  name = 'db_block_size') /&lt;br /&gt;8         (select pval1&lt;br /&gt;9          from   sys.aux_stats$&lt;br /&gt;10          where  sname = 'SYSSTATS_MAIN' and&lt;br /&gt;11                 pname = 'MREADTIM')&lt;br /&gt;12         /1024 sys_stat_mread_speed&lt;br /&gt;13  from dual&lt;br /&gt;14  /&lt;br /&gt;&lt;br /&gt;SYS_STAT_MREAD_SPEED&lt;br /&gt;--------------------&lt;br /&gt;        42.4028269&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:00.00&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So the system statistics suggest a multiblock read performance of 42.4Mb/sec, and the Count(*) timing of 13.12sec and table size of 512Mb suggest 39Mb/sec.&lt;br /&gt;&lt;br /&gt;This is just a single-threaded multiblock read on an otherwise quiescent system and so probably represents the upper limit on what this system could achieve, rather than what it would achieve in a multiuser environment, but the method seems useful as some kind of benchmark. Shouldn't it be possible to perform some kind of real-world comparison on this basis, if the system stats were collected during a period of multiuser activity?&lt;br /&gt;&lt;br /&gt;I intuitively feel that this calculation would represent an approximation of how many Mb/sec you could expect from each thread of a parallel query, providing that neither the CPUs nor the disk subsystem are choking performance. So if you knew that you could run a degree 8 scan of a table without any part of the system choking, this ought to tell you hw long such a scan would take.&lt;br /&gt;&lt;br /&gt;I think.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;Update 14-Dec-2005&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Following comments by Jonathan Lewis I ran a slightly modified version of the script to start a 10046 level 8 trace before the start of system statistics gathering. Here's a summary in which I've just included truncated SQL statements and wait events (and summarized those where appropriate):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;BEGIN dbms_stats.gather_system_stats('START'); END;                             &lt;br /&gt;SELECT /*+ rule */ VALUE FROM V$PARAMETER WHERE UPPER(NAME) = 'STATISTICS_LEVEL'&lt;br /&gt;SELECT S.SNAME, S.PNAME, S.PVAL1, S.PVAL2 FROM AUX_STATS$ S WHERE S.SNAME LIKE 'S&lt;br /&gt;WAIT #2: nam='db file sequential read' ela= 230 p1=1 p2=4434 p3=1&lt;br /&gt;WAIT #2: nam='db file sequential read' ela= 139 p1=1 p2=4426 p3=1&lt;br /&gt;SELECT SUM(KCFIOSBR) SBLKRDS, SUM(KCFIOSBT)*10 SBLKRDTIM, SUM(KCFIOMBR) MBLKRDS,&lt;br /&gt;SELECT S1.VALUE - S2.VALUE MBREADS FROM V$SYSSTAT S1, V$SYSSTAT S2 WHERE S1.NAME&lt;br /&gt;delete from  sys.cache_stats_0$&lt;br /&gt;WAIT #20: nam='db file sequential read' ela= 8581 p1=1 p2=5425 p3=1&lt;br /&gt;WAIT #20: nam='db file scattered read' ela= 1069 p1=1 p2=5426 p3=7&lt;br /&gt;WAIT #20: nam='db file scattered read' ela= 10004 p1=1 p2=51393 p3=8&lt;br /&gt;WAIT #20: nam='db file scattered read' ela= 13039 p1=1 p2=64049 p3=8&lt;br /&gt;WAIT #20: nam='db file scattered read' ela= 3618 p1=1 p2=64073 p3=8&lt;br /&gt;WAIT #20: nam='db file scattered read' ela= 10195 p1=1 p2=80513 p3=8&lt;br /&gt;WAIT #20: nam='db file scattered read' ela= 12877 p1=1 p2=88233 p3=8&lt;br /&gt;WAIT #20: nam='db file sequential read' ela= 4380 p1=2 p2=57 p3=1&lt;br /&gt;WAIT #20: nam='db file sequential read' ela= 498 p1=1 p2=5434 p3=1&lt;br /&gt;WAIT #20: nam='db file sequential read' ela= 142 p1=1 p2=5435 p3=1&lt;br /&gt;WAIT #20: nam='db file sequential read' ela= 175 p1=1 p2=88257 p3=1&lt;br /&gt;SELECT NVL(VALUE,'8.0') FROM V$PARAMETER WHERE NAME = 'compatible'&lt;br /&gt;select sysdate, SYSDATE + 10/24/60 from dual&lt;br /&gt;DECLARE job BINARY_INTEGER := 1; broken BOOLEAN := TRUE; next_date DATE := SYSDAT&lt;br /&gt;SELECT NAME FROM SYS.USER$ WHERE USER# = :B1&lt;br /&gt;WAIT #22: nam='db file sequential read' ela= 11775 p1=1 p2=98 p3=1&lt;br /&gt;WAIT #22: nam='db file sequential read' ela= 150 p1=1 p2=91 p3=1&lt;br /&gt;SELECT NAME FROM SYS.USER$ WHERE USER# = UID&lt;br /&gt;SELECT JOBSEQ.NEXTVAL FROM DUAL&lt;br /&gt;INSERT INTO SYS.JOB$ (JOB, LOWNER, POWNER, COWNER, NEXT_DATE, INTERVAL#, FLAG, WH&lt;br /&gt;WAIT #25: nam='db file sequential read' ela= 2854 p1=1 p2=1473 p3=1&lt;br /&gt;WAIT #25: nam='db file sequential read' ela= 263 p1=1 p2=1475 p3=1&lt;br /&gt;WAIT #25: nam='db file sequential read' ela= 1069 p1=1 p2=1482 p3=1&lt;br /&gt;WAIT #25: nam='db file sequential read' ela= 1132 p1=1 p2=1490 p3=1&lt;br /&gt;UPDATE SYS.SNAP$ SET AUTO_FUN = :B2 , AUTO_DATE = :B1 WHERE (SOWNER,VNAME) IN (SE&lt;br /&gt;WAIT #26: nam='db file sequential read' ela= 577 p1=1 p2=1497 p3=1&lt;br /&gt;WAIT #26: nam='db file scattered read' ela= 260 p1=1 p2=1498 p3=2&lt;br /&gt;UPDATE SYS.JOB$ SET FIELD1 = :B2 WHERE SYS.JOB$.JOB = :B1&lt;br /&gt;update sys.job$ set cowner=:2, nlsenv=:3, env=:4 where job=:1&lt;br /&gt;DELETE FROM SYS.AUX_STATS$ WHERE SNAME = 'SYSSTATS_INFO'&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_INFO', 'STATUS', NULL, :B1 )&lt;br /&gt;WAIT #29: nam='db file sequential read' ela= 1898 p1=1 p2=4425 p3=1&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_INFO', 'DSTART', NULL, :B1 )&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_INFO', 'DSTOP', NULL, :B1 )&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_INFO', 'FLAGS', :B1 , NULL)&lt;br /&gt;insert into sys.wri$_optstat_aux_history (savtime, sname, pname, pval1, pval2) se&lt;br /&gt;WAIT #33: nam='db file sequential read' ela= 179 p1=3 p2=1028 p3=1&lt;br /&gt;WAIT #33: nam='db file sequential read' ela= 27820 p1=3 p2=1019 p3=1&lt;br /&gt;WAIT #33: nam='db file sequential read' ela= 170 p1=3 p2=1018 p3=1&lt;br /&gt;WAIT #33: nam='db file sequential read' ela= 138 p1=3 p2=1017 p3=1&lt;br /&gt;WAIT #33: nam='db file sequential read' ela= 228 p1=3 p2=1024 p3=1&lt;br /&gt;WAIT #33: nam='db file sequential read' ela= 3783 p1=2 p2=9 p3=1&lt;br /&gt;WAIT #33: nam='db file sequential read' ela= 5176 p1=2 p2=7095 p3=1&lt;br /&gt;DELETE FROM SYS.AUX_STATS$ WHERE SNAME = 'SYSSTATS_MAIN'&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_MAIN', 'CPUSPEEDNW', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_MAIN', 'IOSEEKTIM', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_MAIN', 'IOTFRSPEED', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_MAIN', 'SREADTIM', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_MAIN', 'MREADTIM', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_MAIN', 'CPUSPEED', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_MAIN', 'MBRC', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_MAIN', 'MAXTHR', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_MAIN', 'SLAVETHR', :B1 , NULL)&lt;br /&gt;DELETE FROM SYS.AUX_STATS$ WHERE SNAME = 'SYSSTATS_TEMP'&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_TEMP', 'SBLKRDS', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_TEMP', 'SBLKRDTIM', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_TEMP', 'MBLKRDS', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_TEMP', 'MBLKRDTIM', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_TEMP', 'CPUCYCLES', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_TEMP', 'CPUTIM', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_TEMP', 'JOB', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_TEMP', 'CACHE_JOB', :B1 , NULL)&lt;br /&gt;INSERT INTO SYS.AUX_STATS$ VALUES ('SYSSTATS_TEMP', 'MBRTOTAL', :B1 , NULL)&lt;br /&gt;insert into sys.wri$_optstat_opr (operation, target, start_time,  end_time) value&lt;br /&gt;WAIT #3: nam='db file sequential read' ela= 181 p1=3 p2=1035 p3=1&lt;br /&gt;WAIT #3: nam='db file sequential read' ela= 126 p1=3 p2=1034 p3=1&lt;br /&gt;WAIT #3: nam='db file sequential read' ela= 124 p1=3 p2=1033 p3=1&lt;br /&gt;WAIT #3: nam='db file sequential read' ela= 123 p1=3 p2=1040 p3=1&lt;br /&gt;WAIT #3: nam='db file sequential read' ela= 4169 p1=2 p2=25 p3=1&lt;br /&gt;WAIT #3: nam='db file sequential read' ela= 665 p1=2 p2=71 p3=1&lt;br /&gt;WAIT #3: nam='db file sequential read' ela= 127 p1=3 p2=1044 p3=1&lt;br /&gt;WAIT #16: nam='log file sync' ela= 201 p1=342 p2=0 p3=0&lt;br /&gt;WAIT #16: nam='SQL*Net message to client' ela= 4 p1=1111838976 p2=1 p3=0&lt;br /&gt;WAIT #16: nam='SQL*Net message from client' ela= 2175 p1=1111838976 p2=1 p3=0&lt;br /&gt;=====================&lt;br /&gt;PARSING IN CURSOR #3 len=44 dep=0 uid=40 oct=3 lid=40 tim=125426516619 hv=2242715&lt;br /&gt;select /*+ noparallel (t) */ count(*) from t&lt;br /&gt;END OF STMT&lt;br /&gt;PARSE #3:c=0,e=3497,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=125426516613&lt;br /&gt;EXEC #3:c=0,e=90,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=125426516827&lt;br /&gt;WAIT #3: nam='SQL*Net message to client' ela= 5 p1=1111838976 p2=1 p3=0&lt;br /&gt;&lt;br /&gt;(start of summary)&lt;br /&gt;1024*db file scattered read, ela total = 11752972 (avg 11478)&lt;br /&gt;  3*db file sequential read, ela total = 625&lt;br /&gt;(end of summary)&lt;br /&gt;&lt;br /&gt;(start of stat lines for count(*) from t)&lt;br /&gt;STAT #3 id=1 cnt=1 pid=0 pos=1 obj=0 op='SORT AGGREGATE (cr=65590 pr=65537 pw=0 t&lt;br /&gt;STAT #3 id=2 cnt=65535 pid=1 pos=1 obj=260948 op='TABLE ACCESS FULL T (cr=65590 p&lt;br /&gt;(end of stat lines()&lt;br /&gt;&lt;br /&gt;WAIT #3: nam='SQL*Net message from client' ela= 230 p1=1111838976 p2=1 p3=0&lt;br /&gt;WAIT #3: nam='SQL*Net message to client' ela= 2 p1=1111838976 p2=1 p3=0&lt;br /&gt;WAIT #3: nam='SQL*Net message from client' ela= 2549 p1=1111838976 p2=1 p3=0&lt;br /&gt;BEGIN dbms_stats.gather_system_stats('STOP'); END;&lt;br /&gt;SELECT 1 FROM SYS.JOB$ WHERE JOB = :B2 AND POWNER = :B1 FOR UPDATE&lt;br /&gt;DELETE FROM JOB$ WHERE JOB = :B1&lt;br /&gt;UPDATE SYS.SNAP$ SET AUTO_FUN = 'null' WHERE (SOWNER,VNAME) IN (SELECT RC.OWNER,&lt;br /&gt;insert into sys.wri$_optstat_aux_history (savtime, sname, pname, pval1, pval2) se&lt;br /&gt;WAIT #6: nam='db file sequential read' ela= 10237 p1=2 p2=41 p3=1&lt;br /&gt;WAIT #6: nam='db file sequential read' ela= 7822 p1=2 p2=2145 p3=1&lt;br /&gt;DELETE FROM SYS.AUX_STATS$ WHERE SNAME = 'SYSSTATS_TEMP'&lt;br /&gt;insert into sys.wri$_optstat_opr (operation, target, start_time,  end_time) value&lt;br /&gt;WAIT #16: nam='log file sync' ela= 195 p1=388 p2=0 p3=0&lt;br /&gt;WAIT #16: nam='SQL*Net message to client' ela= 4 p1=1111838976 p2=1 p3=0&lt;br /&gt;WAIT #16: nam='SQL*Net message from client' ela= 3981 p1=1111838976 p2=1 p3=0&lt;br /&gt;select pname,&lt;br /&gt;      pval1&lt;br /&gt;from   sys.aux_stats$&lt;br /&gt;where  sname = 'SYSSTATS_MAIN'&lt;br /&gt;WAIT #5: nam='SQL*Net message to client' ela= 3 p1=1111838976 p2=1 p3=0&lt;br /&gt;WAIT #5: nam='SQL*Net message from client' ela= 217 p1=1111838976 p2=1 p3=0&lt;br /&gt;WAIT #5: nam='SQL*Net message to client' ela= 2 p1=1111838976 p2=1 p3=0&lt;br /&gt;WAIT #5: nam='SQL*Net message from client' ela= 8720 p1=1111838976 p2=1 p3=0&lt;br /&gt;select (select pval1&lt;br /&gt;       from   sys.aux_stats$&lt;br /&gt;       where  sname = 'SYSSTATS_MAIN' and&lt;br /&gt;              pname = 'MBRC') *&lt;br /&gt;      (select to_number(value) block_size&lt;br /&gt;       from   v$parameter&lt;br /&gt;       where  name = 'db_block_size') /&lt;br /&gt;      (select pval1&lt;br /&gt;       from   sys.aux_stats$&lt;br /&gt;       where  sname = 'SYSSTATS_MAIN' and&lt;br /&gt;              pname = 'MREADTIM')&lt;br /&gt;      /1024 sys_stat_mread_speed&lt;br /&gt;from dual&lt;br /&gt;WAIT #16: nam='SQL*Net message to client' ela= 3 p1=1111838976 p2=1 p3=0&lt;br /&gt;WAIT #16: nam='SQL*Net message from client' ela= 838 p1=1111838976 p2=1 p3=0&lt;br /&gt;WAIT #16: nam='SQL*Net message to client' ela= 3 p1=1111838976 p2=1 p3=0&lt;br /&gt;WAIT #16: nam='SQL*Net message from client' ela= 2492 p1=1111838976 p2=1 p3=0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So it does look to me like the sequential reads are mostly generated by recursive SQL, although there are a few associated with the count(*) from t.&lt;br /&gt;&lt;br /&gt;Not a clue on the thread statistics though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113450038219629225?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113450038219629225/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113450038219629225' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113450038219629225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113450038219629225'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/playing-with-system-statistics.html' title='Playing With System Statistics'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113449661515665234</id><published>2005-12-13T10:53:00.000-07:00</published><updated>2005-12-13T10:56:55.156-07:00</updated><title type='text'>New Index Section</title><content type='html'>I added a new index section (is that the right term?) for articles about materialized views, since I seem to be writing so much about them.&lt;br /&gt;&lt;br /&gt;Yesterday evening I felt nauseous while writing my next MV-related article, and I thought it was just an overdose of trace files or an allergy to consistent gets, but thankfully it turned out that rebooting my computer had led to a smell of burning insulation filling the room.&lt;br /&gt;&lt;br /&gt;So, nothing to worry about there then.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113449661515665234?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113449661515665234/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113449661515665234' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113449661515665234'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113449661515665234'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/new-index-section.html' title='New Index Section'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113449557732181898</id><published>2005-12-13T10:33:00.000-07:00</published><updated>2005-12-13T10:39:37.363-07:00</updated><title type='text'>System Statistics</title><content type='html'>In 9i onwards we can use DBSMS_STATS.GATHER_SYSTEM_STATS to get some becnchmarks for system performance that are then usable by the cost-based optimizer, and it seems to me that these statistics ought to be a pretty good way of comparing different hardware (cutting through all the CPU GHz, disk speed, controller caching comparisons that are so detailed that it's virtually impossible to get useful information from them).&lt;br /&gt;&lt;br /&gt;There don't seem to be many reference values for system statistics available anywhere, so over at the Dizwell Forum I started a thread to collect them -- if you have a moment then I'd appreciate it if you could post a very brief description of your hardware and the results of:&lt;br /&gt;&lt;pre&gt;select pname,pval1 from sys.aux_stats$&lt;br /&gt;where sname = 'SYSSTATS_MAIN'&lt;br /&gt;/&lt;/pre&gt;&lt;br /&gt;Hopefully something analytical will come out of it.&lt;br /&gt;&lt;br /&gt;If you don't want to register at Dizwell then feel free to reply below: thanks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113449557732181898?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113449557732181898/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113449557732181898' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113449557732181898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113449557732181898'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/system-statistics.html' title='System Statistics'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113439603220516930</id><published>2005-12-12T07:00:00.000-07:00</published><updated>2005-12-12T07:15:42.476-07:00</updated><title type='text'>A Little Culture</title><content type='html'>Almost unbelievably we managed to get away for a whole night, and went to Denver for a bit of culture with the &lt;a href="http://www.coloradosymphony.org/"&gt;Colorado Symphony Orchestra&lt;/a&gt; and &lt;a href="http://www.langlang.com/"&gt;this&lt;/a&gt; young whipper-snapper playing Chopin. Twenty-three years old, and twenty years experience as a piano player. Strewth.&lt;br /&gt;&lt;br /&gt;Anyway, I feel like a crucial decision point coming up -- keep with the CD collection or start investing in SACD (and at some point the equipment to play them properly). I hate these technical decisions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113439603220516930?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113439603220516930/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113439603220516930' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113439603220516930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113439603220516930'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/little-culture.html' title='A Little Culture'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113415931679406503</id><published>2005-12-09T13:13:00.000-07:00</published><updated>2005-12-09T13:15:16.840-07:00</updated><title type='text'>MV Articles</title><content type='html'>I think I'm going to go back and change some article names: "Reducing The Work Of Refreshing Multiple Materialized Views" is not proving to be a good description, so I'll switch over to "Optimizing Materialized Views" as a stub.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113415931679406503?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113415931679406503/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113415931679406503' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113415931679406503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113415931679406503'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/mv-articles_09.html' title='MV Articles'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113410865838088008</id><published>2005-12-08T23:01:00.000-07:00</published><updated>2005-12-09T13:32:08.270-07:00</updated><title type='text'>Optimizing Materialized Views Part IV: Introduction to HOLAP Cubes</title><content type='html'>&lt;p&gt;&lt;b&gt;&lt;i&gt;A Quick Recap&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;In part II of this series I described the mechanism by which the direct path enhancement to materialized view fast refresh, and the benefits it bestows.&lt;br /&gt;&lt;br /&gt;In part III I showed how we can identify circumstances in which we can entirely bypass Oracle's internal mechanism for fast refresh and instead use our own insert statement to maintain the materialized view. Tricky stuff, and not entirely conventional, but powerful nonetheless.&lt;br /&gt;&lt;br /&gt;In this part IV we return to the straight and narrow of accepted practice, albeit somewhat at the cutting edge, by looking at a type of materialized view. More accurately we will look at a type of query which we can materialize in an MV and which specifically addresses the subject of &lt;i&gt;multiple&lt;/i&gt; MV refreshes.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;Hierarchical OLAP Cubes&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;One of the items of work that is carried out in the refresh of a materialized view is the scan of the changed data in the master table. When you are refreshing multiple materialized views based directly on the same fact table then that change data gets scanned multiple times. We might spend time looking at how we can reduce the work of these multiple scans, but how much more satisfactory it is to find a way of eliminating all but one of the scans entirely. We will do this by taking advantage of the ability of Oracle to aggregate to multiple levels in a single SQL statement.&lt;br /&gt;&lt;br /&gt;You'll find this documented in various places under the subject of &lt;a href="http://otn.oracle.com/pls/db10g/db10g.drilldown?remark=quick_search&amp;word=Hierarchical+cubes&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;book=&amp;preference="&gt;Hierarchical Cubes&lt;/a&gt;, most usefully in the Data Warehousing Guide, and the principle is fairly simple. In just the same way as a regular materialized view holds a single level of aggregation (for example at the level of "location code" and "transaction month") a hierarchical cube can hold a number of different aggregation levels in a single materialized view. Don't be misled or intimidated by the the word “cube” by the way. Other than a simple change in the syntax of the MV query and an additional concept or two there is nothing here that is much of a paradigm shift for us humble databasers.&lt;/p&gt;  &lt;p&gt;So, a hierarchical cube hold multiple aggregation levels in a single table. We have been using as an example a fact table with a logical structure as follows:&lt;/p&gt;  &lt;pre&gt;create table master&lt;br /&gt; (&lt;br /&gt; location_cd  number not null,&lt;br /&gt; tx_timestamp date   not null,&lt;br /&gt; product_cd   number not null,&lt;br /&gt; tx_qty       number not null,&lt;br /&gt; tx_cst       number not null&lt;br /&gt; )&lt;br /&gt;/&lt;/pre&gt; &lt;p&gt;&lt;br /&gt;Based on such a table we have a great many choices of aggregation level that we might find use for. In general we might expect to use the following:&lt;/p&gt;  &lt;ul&gt; &lt;li&gt;&lt;p&gt;location_cd and trunc(tx_timestamp,'D')&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p&gt;product_cd and trunc(tx_timestamp,'D')&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p&gt;trunc(tx_timestamp,'D')&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p&gt;trunc(tx_timestamp,'MM')&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p&gt;location_cd and product_cd and trunc(tx_timestamp,'D')&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p&gt;location_cd and product_cd and tx_timestamp (if not unique in  the master table, and even then see “&lt;a href="http://oraclesponge.blogspot.com/2005/12/mysterious-benefit-of-completely.html"&gt;The  Mysterious Benefit Of Completely Redundant Materialized Views&lt;/a&gt;”)&lt;/p&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Many of these materialized views are going to be very small, and it seems like a shame to be scanning many millions of new rows multiple times on their account. Maybe we might modify our strategy to base some of the higher level MV's on other lower level MV's, and that's an option that we'll look at later on, but for now let us see what an hierarchical cube can do for us.&lt;/p&gt;  &lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p&gt;&lt;i&gt;&lt;b&gt;Syntax&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;  &lt;p&gt;There are a number of &lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10736/aggreg.htm#DWHSG019"&gt;slightly different syntaxes&lt;/a&gt; through which multilevel aggregation can be enabled, but the one that I prefer myself is the "Grouping Sets" method. This is because it gives me exact control over which aggregation levels I want to be "materialized" with the minimum of brainwork.&lt;br /&gt;&lt;br /&gt;For example, consider the following syntax:&lt;/p&gt;  &lt;pre&gt;Select&lt;br /&gt;   product_cd,&lt;br /&gt;   location_cd,&lt;br /&gt;   trunc(tx_timestamp,'MM') tx_month,&lt;br /&gt;   sum(tx_qty) s_tx_qty,&lt;br /&gt;   sum(tx_cst) s_tx_cst,&lt;br /&gt;   count(*)    c_star&lt;br /&gt;from&lt;br /&gt;   master&lt;br /&gt;group by&lt;br /&gt;   grouping sets&lt;br /&gt;      ((trunc(tx_timestamp,'MM'),product_cd ),&lt;br /&gt;       (trunc(tx_timestamp,'MM'),location_cd));&lt;/pre&gt; &lt;p&gt; Those last three lines are what makes this SQL “special”, by producing multiple levels of aggregation from a single SQL statement. In this case we have a single statement generating the aggregations at the month/product level &lt;i&gt;and&lt;/i&gt; the month/location level.&lt;/p&gt;  &lt;p&gt;Once you have grasped this it is of course easy to extend the syntax to more levels, and here is an example with six of them:&lt;/p&gt;  &lt;pre&gt;Select&lt;br /&gt;   product_cd,&lt;br /&gt;   location_cd,&lt;br /&gt;   trunc(tx_timestamp,'MM') tx_month,&lt;br /&gt;   sum(tx_qty) s_tx_qty,&lt;br /&gt;   sum(tx_cst) s_tx_cst,&lt;br /&gt;   count(*)    c_star&lt;br /&gt;from&lt;br /&gt;   master&lt;br /&gt;group by&lt;br /&gt;   grouping sets&lt;br /&gt;      ((trunc(tx_timestamp,'MM'),product_cd),&lt;br /&gt;       (trunc(tx_timestamp,'MM'),location_cd),&lt;br /&gt;       (trunc(tx_timestamp,'MM')),&lt;br /&gt;       (product_cd,location_cd),&lt;br /&gt;       (product_cd),&lt;br /&gt;       (location_cd));&lt;/pre&gt; &lt;p&gt; Naturally when we compute multiple aggregation levels in a single query result we need a reliable method of distinguishing between the aggregation levels. We cannot just select a Sum() of a metric column of a cube like this without inflating the required result by some integer factor (six, in this last example), and it follows that every single query that gets rewritten against such a multilevel aggregation needs to select the rows of only a single aggregation level, and exclude all others.&lt;/p&gt;  &lt;p&gt;To enable this we use a "&lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10736/aggreg.htm#sthref1547"&gt;Grouping&lt;/a&gt;" function, and the most convenient form for our purposes is GROUPING_ID. This identifies in a single value the aggregation (or “grouping” if you wish) level of a row by returning a bit vector of ... well just read about it &lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10736/aggreg.htm#sthref1556"&gt;here&lt;/a&gt;. But long-story-short, if you are going to define a materialized view with multiple aggregation levels then you include the GROUPING_ID function based on all the dimensions included as grouping levels. Thus we would write:&lt;/p&gt;  &lt;pre&gt;Select&lt;br /&gt;   grouping_id&lt;br /&gt;    (trunc(tx_timestamp,'MM'),&lt;br /&gt;     product_cd,&lt;br /&gt;     location_cd) gid,&lt;br /&gt;   product_cd,&lt;br /&gt;   location_cd,&lt;br /&gt;   trunc(tx_timestamp,'MM') tx_month,&lt;br /&gt;   sum(tx_qty) s_tx_qty,&lt;br /&gt;   sum(tx_cst) s_tx_cst,&lt;br /&gt;   count(*)    c_star&lt;br /&gt;from&lt;br /&gt;   master&lt;br /&gt;group by&lt;br /&gt;   grouping sets&lt;br /&gt;   ((trunc(tx_timestamp,'MM'),product_cd),&lt;br /&gt;    (trunc(tx_timestamp,'MM'),location_cd));&lt;/pre&gt; &lt;p&gt; or:&lt;/p&gt;  &lt;pre&gt;select&lt;br /&gt;   grouping_id&lt;br /&gt;    (trunc(tx_timestamp,'MM'),&lt;br /&gt;     product_cd,&lt;br /&gt;     location_cd) gid,&lt;br /&gt;   product_cd,&lt;br /&gt;   location_cd,&lt;br /&gt;   trunc(tx_timestamp,'MM') tx_month,&lt;br /&gt;   sum(tx_qty) s_tx_qty,&lt;br /&gt;   sum(tx_cst) s_tx_cst,&lt;br /&gt;   count(*)    c_star&lt;br /&gt;from&lt;br /&gt;   master&lt;br /&gt;group by&lt;br /&gt;   grouping sets&lt;br /&gt;      ((trunc(tx_timestamp,'MM'),product_cd),&lt;br /&gt;       (trunc(tx_timestamp,'MM'),location_cd),&lt;br /&gt;       (product_cd,location_cd),&lt;br /&gt;       (trunc(tx_timestamp,'MM')),&lt;br /&gt;       (product_cd),&lt;br /&gt;       (location_cd));&lt;/pre&gt; &lt;p&gt; Notice that we just include each dimension column once there, irrespective of how many times it is included in different grouping sets.&lt;br /&gt;&lt;br /&gt;This seems like an appropriate time to look at the execution of such queries:&lt;/p&gt;  &lt;pre&gt;drop table master&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;create table master&lt;br /&gt;   (&lt;br /&gt;   location_cd  not null,&lt;br /&gt;   tx_timestamp not null,&lt;br /&gt;   product_cd   not null,&lt;br /&gt;   tx_qty       not null,&lt;br /&gt;   tx_cst       not null&lt;br /&gt;   )&lt;br /&gt;pctfree 0&lt;br /&gt;nologging&lt;br /&gt;as&lt;br /&gt;select&lt;br /&gt;   trunc(dbms_random.value(1,10)),&lt;br /&gt;   to_date('01-jan-2005','DD-Mon-YYYY')&lt;br /&gt;      + dbms_random.value(0,30),&lt;br /&gt;   trunc(dbms_random.value(1,10000)),&lt;br /&gt;   trunc(dbms_random.value(1,10)),&lt;br /&gt;   trunc(dbms_random.value(1,100),2)&lt;br /&gt;from&lt;br /&gt;   dual&lt;br /&gt;connect by&lt;br /&gt;   1=1 and&lt;br /&gt;   level &lt; 1000001;&lt;br /&gt;&lt;br /&gt;begin&lt;br /&gt;   dbms_stats.gather_table_stats&lt;br /&gt;     (ownname    =&gt; user,&lt;br /&gt;      tabname    =&gt; 'MASTER',&lt;br /&gt;      method_opt =&gt; 'for all columns size 254');&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;SQL&gt; select * from table(dbms_xplan.display());&lt;br /&gt;&lt;br /&gt;PLAN_TABLE_OUTPUT&lt;br /&gt;--------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;Plan hash value: 4085247581&lt;br /&gt;&lt;br /&gt;----------------------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation                  | Name                        | Rows  | Bytes | Cost (%CPU)| Time     |&lt;br /&gt;----------------------------------------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT           |                             |  1000K|    82M|   667   (2)| 00:00:08 |&lt;br /&gt;|   1 |  TEMP TABLE TRANSFORMATION |                             |       |       |            |          |&lt;br /&gt;|   2 |   LOAD AS SELECT           |                             |       |       |            |          |&lt;br /&gt;|   3 |    TABLE ACCESS FULL       | MASTER                      |  1000K|    20M|   659   (2)| 00:00:08 |&lt;br /&gt;|   4 |   LOAD AS SELECT           |                             |       |       |            |          |&lt;br /&gt;|   5 |    SORT GROUP BY           |                             |     1 |    48 |     3  (34)| 00:00:01 |&lt;br /&gt;|   6 |     TABLE ACCESS FULL      | SYS_TEMP_0FD9D6607_12037633 |     1 |    48 |     2   (0)| 00:00:01 |&lt;br /&gt;|   7 |   LOAD AS SELECT           |                             |       |       |            |          |&lt;br /&gt;|   8 |    SORT GROUP BY           |                             |     1 |    48 |     3  (34)| 00:00:01 |&lt;br /&gt;|   9 |     TABLE ACCESS FULL      | SYS_TEMP_0FD9D6607_12037633 |     1 |    48 |     2   (0)| 00:00:01 |&lt;br /&gt;|  10 |   VIEW                     |                             |     1 |    87 |     2   (0)| 00:00:01 |&lt;br /&gt;|  11 |    TABLE ACCESS FULL       | SYS_TEMP_0FD9D6608_12037633 |     1 |    87 |     2   (0)| 00:00:01 |&lt;br /&gt;----------------------------------------------------------------------------------------------------------&lt;/pre&gt; &lt;p&gt;&lt;br /&gt;Isn't that interesting? It's pretty esoteric stuff, although later on we'll see some real eye-bulgers. There is some kind of temporary structure being used there, but what is its nature? To answer questions of this sort we can run a SQL trace on the query, but I'm going to leave the results of that for another posting because otherwise I'm going to set another new record for length of blog entry. However it is clear that some internal temporary structures are being created to help with the aggregation, so some optimizations are at work here that we will explore in detail another time. For now let us look at some performance comparisions.&lt;/p&gt;  &lt;p&gt;There are three types of comparison of interest here.&lt;/p&gt;  &lt;p&gt;Firstly, how is the performance of a HOLAP query affected by the addition and nature of further aggregation levels? My instinct going into this exercise is that there is a certain overhead involved in using a HOLAP query, based on the existence of all those temporary structures that need to be created. Also I suspect that there could be optimizations that allow lower levels of aggregation to be leveraged in the calculations of higher levels – for example it could be that an aggregation to the (product_cd,location_cd) level can be used as an intermediate result in calculating an aggregation at the (product_cd) and the (location_cd) levels. It could also be that such optimizations are highly dependent on Oracle version.&lt;/p&gt;  &lt;p&gt;Secondly, how does the performance of a HOLAP query compare with running multiple single-level aggregations?&lt;/p&gt;  &lt;p&gt;Thirdly, how do the different forms of syntax – RollUp(), Grouping Sets() and Cube() -- compare performance-wise? Again, this may be very version dependent, and if the optimizations are in place we can expect there to actually be little difference.&lt;/p&gt;  &lt;p&gt;Fourthly, how is all this affected by the new hash-based grouping algorithm of version 10gR2? Without the need for a SORT GROUP BY operation it seems that this might make a real difference to the internal optimizations of the aggregations.&lt;/p&gt;  &lt;p&gt;&lt;i&gt;&lt;b&gt;HOLAP Performance With Different Aggregation Levels&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;  &lt;p&gt;First a hypothesis, or maybe just speculation.&lt;/p&gt;  &lt;p&gt;A HOLAP query potentially contains enough information for the optimizer to tell that there are result sets generated that can then be leveraged to produce further result sets. For example if you are going to aggregate at 10,000,000 row table and generate a 1,000,000 row result set for the grouping (col1, col2) then if the 1,000 row groupings (col1) and (col2) are also required then it makes sense to use the (col1, col2) result set to do so. On the other hand if two result sets (col1, col2) and (col2, col3) are required then there might be an advantage in calculating (col1, col2, col3) as an intermediate step, but it would depend on the sophistication of the optimization and the determination of whether such an intermediate step was worthwhile. If no intermediate set is produced then the original set of rows would be scanned twice, and as long as we can keep our sorts in memory we ought to be able to detect this.&lt;/p&gt;  &lt;p&gt;When thinking about the possibilities for aggregation it makes sense to think of a tree structure of potential intermediate result sets, such as the following&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/8036/953/1600/holap%20tree%201.0.jpg"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/8036/953/320/holap%20tree%201.0.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;That one shows promise for optimization by leveraging the intermediate result sets. However the following one does not:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/8036/953/1600/holap%20tree%202.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger/8036/953/320/holap%20tree%202.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;I'm going to construct a slightly different test data set for this experiment, involving the aggregation of 10,000,000 by three different columns each having around 1000 distinct values. We will try aggregations at a number of different levels and combinations of levels, such as: ((COL1)), ((COL1),(COL2)), ((COL1),(COL1,COL2)), ((col1),(col2),(col3),(col1,col2,col3)), etc. with the intent of exposing us to almost a full range of potential optimizations.&lt;br /&gt;&lt;br /&gt;The methodology for these tests is to execute each query four times, flushing the buffer cache before each one. The average statistics of the last three executions will be taken (with the intent that the recursive calls due to the hard parse of the first execution are thus excluded). Workarea size policy will be set to manual and sufficient sort area allocated to eliminate disk sorts. The host machine and database will be as quiescent as possible, which is not difficult to achieve in this environment.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.... And with that I'm going to break off this entry to let you absorb these ideas, comment back if you wish, and give me time to complete the tests.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113410865838088008?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113410865838088008/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113410865838088008' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113410865838088008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113410865838088008'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/optimizing-materialized-views-part-iv.html' title='Optimizing Materialized Views Part IV: Introduction to HOLAP Cubes'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113407155272364961</id><published>2005-12-08T19:00:00.000-07:00</published><updated>2006-04-12T12:05:27.746-06:00</updated><title type='text'>ORA-12034: materialized view log younger than last refresh</title><content type='html'>Dabblers in the art of the materialisation of views may be used to seeing this error message, and it's often a portent of doom. Metalink Note &lt;a href="https://metalink.oracle.com/metalink/plsql/ml2_documents.showFrameDocument?p_database_id=NOT&amp;p_id=204127.1"&gt;204127.1&lt;/a&gt; tackles it head on with a list of possible causes, but is remiss in advising that a complete refresh is required.&lt;br /&gt;&lt;br /&gt;And thank goodness for that. A multi-gigabyte materialized view based on a multi-multi-gigabyte master table is no joke to perform a complete refresh on, and anything we can do to avoid it is welcome.&lt;br /&gt;&lt;br /&gt;As far as data warehousing is concerned we can trim the fat out of the Metalink note to shortlist our potential causes:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;Previous refresh failed&lt;/li&gt;   &lt;li&gt;Modifying the master table so that changes don't go to the materialized view log (truncate, alter partitions ... drop / truncate ... etc)&lt;/li&gt;   &lt;li&gt;Master table reorganization&lt;/li&gt; &lt;/ul&gt; And here is another prime cause that the note doesn't identify:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;Issuing an MV log purge.&lt;/li&gt; &lt;/ul&gt; All of these potential causes appear to be easily fixable through the simple mechanism of dropping and recreating the materialized view. But I'm not talking about dropping the data here. One of the requirements for this method to be successful is that the materialized view was created on a prebuilt table. If this is the case, and it is possible to find out if it is or not based on the BUILD_MODE column of USER_MVIEWS, then in the event of a refresh failure we can:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Drop the materialized view.&lt;/li&gt;   &lt;li&gt;Do whatever is required (if anything) to bring the master table and the MV back into synchronization (delete data from master, or add data to MV).&lt;/li&gt;   &lt;li&gt;Recreate the MV, again using the ON PREBUILT TABLE clause obviously.&lt;/li&gt;&lt;li&gt;Erm ...&lt;/li&gt;   &lt;li&gt;That's it.&lt;/li&gt; &lt;/ol&gt;Doubtless you script hounds will be wanting to see a test of this, huh?&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;create table m (col1 number);&lt;br /&gt;&lt;br /&gt;create materialized view log on m&lt;br /&gt;with rowid (col1)&lt;br /&gt;including new values;&lt;br /&gt;&lt;br /&gt;create table&lt;br /&gt;     m_mv_cstar&lt;br /&gt;as&lt;br /&gt;select count(*) c_star&lt;br /&gt;from   m;&lt;br /&gt;&lt;br /&gt;create materialized view m_mv_cstar&lt;br /&gt; on prebuilt table&lt;br /&gt; refresh fast&lt;br /&gt; on commit&lt;br /&gt;as&lt;br /&gt;select count(*) c_star&lt;br /&gt;from   m;&lt;br /&gt;&lt;br /&gt;insert into m values (1);&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That gets us a successfully fast refreshing materialized view. Now we break it.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;drop materialized view log on m;&lt;br /&gt;&lt;br /&gt;create materialized view log on m&lt;br /&gt;with rowid (col1)&lt;br /&gt;including new values;&lt;br /&gt;&lt;br /&gt;insert into m values (1);&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That ought to get you the ORA-12034 error, and this is the time to go and check whether any other materialized views has successfully refreshed and whether the change to the master table is still intact or whether that has been rolled back. In this case the change to m ought to have been rolled back.&lt;br /&gt;&lt;br /&gt;So now we fix the problem of the ORA-12034 without a complete refresh of the materialized view.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;drop  materialized view m_mv;&lt;br /&gt;&lt;br /&gt;create materialized view m_mv&lt;br /&gt;  on prebuilt table&lt;br /&gt;  refresh fast&lt;br /&gt;  on commit&lt;br /&gt;as&lt;br /&gt;select count(*) c_star&lt;br /&gt;from   m;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If by some chance you had mislaid the definition of your materialized view then use the following to retrieve it.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Set Long 100000 Pagesize 0&lt;br /&gt;&lt;br /&gt;Select  DBMS_Metadata.Get_DDL('MATERIALIZED_VIEW','M_MV_CSTAR') From Dual;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Note the underscore in the MATERIALIZED_VIEW there. Forget that and you'll receive a baffling:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; 1* Select  DBMS_Metadata.Get_DDL('MATERIALIZED VIEW','M_MV_CSTAR') From Dual&lt;br /&gt;SQL&gt; /&lt;br /&gt;ERROR:&lt;br /&gt;ORA-31600: invalid input value MATERIALIZED VIEW for parameter OBJECT_TYPE in&lt;br /&gt;function GET_DDL&lt;br /&gt;ORA-06512: at "SYS.DBMS_METADATA", line 2576&lt;br /&gt;ORA-06512: at "SYS.DBMS_METADATA", line 2627&lt;br /&gt;ORA-06512: at "SYS.DBMS_METADATA", line 4220&lt;br /&gt;ORA-06512: at line 1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So have we successfully recovered from the error?&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;insert into m values (1);&lt;br /&gt;&lt;br /&gt;commit;&lt;br /&gt;&lt;br /&gt;select * from m;&lt;br /&gt;&lt;br /&gt;select * from m_mv_cstar;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Hopefully that demonstrates that we have.&lt;br /&gt;&lt;br /&gt;So, is there a downside to this? Well if you have never run a complete refresh on your materialized view, or created it with a "build immediate" clause, then you will not get the comfort of a STALENESS of "FRESH" and will instead be stuck with the disturbing "UNKNOWN". Relax -- it's just that although you know that the materialized view is fresh, Oracle does not trust you. But then there are so many events that can break the "FRESH" staleness of your materialized view that you should treat FRESH MV's as a rare treat and not get used to them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113407155272364961?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113407155272364961/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113407155272364961' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113407155272364961'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113407155272364961'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/ora-12034-materialized-view-log.html' title='ORA-12034: materialized view log younger than last refresh'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113405788389425886</id><published>2005-12-08T09:00:00.000-07:00</published><updated>2005-12-08T09:04:43.926-07:00</updated><title type='text'>Yahoo Instant Messenger Out, Trillian In</title><content type='html'>Working remotely from my client as I do, I make a lot of use of instant messaging. I made the serious error of upgrading to the latest version and have watched in amusement as it's memory usage often goes northwards of hundreds of megabytes. The record was 1.2Gb ... nice!&lt;br /&gt;&lt;br /&gt;Even when freshly started it squats there hogging 15Mb, and usually hovers between 30Mb and 50Mb, which is inexcusable for software that basically lets me type stuff to other people.&lt;br /&gt;&lt;br /&gt;So Yahoo Instant Messenger is officially Bad Software, and I've replaced it with Trillian Basic 3.1 ... I'll be watching it very closely, but so far it hasn't done anything unpleasant and uses a fraction of the memory.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113405788389425886?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113405788389425886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113405788389425886' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113405788389425886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113405788389425886'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/yahoo-instant-messenger-out-trillian.html' title='Yahoo Instant Messenger Out, Trillian In'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113396924550648403</id><published>2005-12-07T08:24:00.000-07:00</published><updated>2005-12-07T09:14:24.070-07:00</updated><title type='text'>Brrrr ...</title><content type='html'>A little chilly this morning ... -2F/-19C&lt;br /&gt;&lt;br /&gt;Oh,  and guess who forgot to put the car in the garage last night?&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/8036/953/1600/dsc02218.jpg"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/8036/953/320/dsc02218.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Update:&lt;/span&gt; Guess who &lt;span style="font-style: italic;"&gt;wisely&lt;/span&gt; decided to not put the car in the garage for fear of the garage door freezing immovably to the ground? That's right, me. I'm a genius.&lt;br /&gt;&lt;br /&gt;Peterson AFB was on a two hour delay this morning, and the school district upgraded their two hour delay to a complete closure so I may be getting the company of a stir-crazy six year old boy. That'll be ... uh ... great.&lt;br /&gt;&lt;br /&gt;On a positive note though, when it's this cold you don't find your vehicle encased in a solid sheet of ice in the morning. The snow just brushes straight off, sometimes into the top of an artfully placed boot.&lt;br /&gt;&lt;br /&gt;It looks like it'll be hanging around a while as it's not due to get above freezing for a couple of days. We usually rely on sun + altitude + gravel to get the roads cleared, and it's pretty successful if you ignore the broken windshields and scratched paint. After our recent few days of cold our local roads are a sheet of inch-thick ice though, so that old advice that most accidents happen within five minutes of home is very true -- often five minutes can be only a hundred yards or so.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113396924550648403?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113396924550648403/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113396924550648403' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113396924550648403'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113396924550648403'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/brrrr.html' title='Brrrr ...'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113277599553123549</id><published>2005-12-06T19:00:00.000-07:00</published><updated>2005-12-06T12:22:38.956-07:00</updated><title type='text'>The Mysterious Benefit Of Completely Redundant Materialized Views</title><content type='html'>&lt;p style="margin-bottom: 0in;"&gt;&lt;b&gt;A Scenario&lt;/b&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;You've just started working on a new data warehouse project, and you're familiarizing yourself with the database schema. You are looking at a simple table that stores transactional information and which is defined as follows:&lt;/p&gt;  &lt;pre&gt;create table master&lt;br /&gt;(&lt;br /&gt;transaction_cd number not null,&lt;br /&gt;location_cd    number not null,&lt;br /&gt;tx_timestamp   date   not null,&lt;br /&gt;product_cd     number not null,&lt;br /&gt;tx_qty         number not null,&lt;br /&gt;tx_cst         number not null&lt;br /&gt;)&lt;br /&gt;/&lt;br /&gt;alter table master&lt;br /&gt;add constraint xpkmaster primary key (transaction_cd)&lt;br /&gt;/&lt;br /&gt;&lt;/pre&gt; &lt;p style="margin-bottom: 0in;"&gt; Plus various foreign keys, indexes and other stuff of course.&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;Built upon this table are a number of materialized views, one of which has the following definition:&lt;/p&gt;  &lt;pre&gt;create materialized view&lt;br /&gt;master_mv1&lt;br /&gt;...&lt;br /&gt;Enable Query Rewrite&lt;br /&gt;As&lt;br /&gt;Select&lt;br /&gt;transaction_cd,&lt;br /&gt;location_cd,&lt;br /&gt;product_cd,&lt;br /&gt;tx_timestamp,&lt;br /&gt;sum(tx_qty) s_tx_qty,&lt;br /&gt;sum(tx_cst) s_tx_cst,&lt;br /&gt;count(*)    c_star&lt;br /&gt;from&lt;br /&gt;master&lt;br /&gt;group by&lt;br /&gt;transaction_cd,&lt;br /&gt;location_cd,&lt;br /&gt;product_cd,&lt;br /&gt;tx_timestamp&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt; &lt;p style="margin-bottom: 0in;"&gt; If you've spotted that all of the attribute columns of the master table are included in the materialized view, and one of those attributes is defined as the primary key of the master table, then you will correctly conclude the following: &lt;i&gt;the materialized view is completely redundant&lt;/i&gt;. It stores exactly the same data as the master table.&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;So, simple question. Why go to the trouble of creating such an abominable waste of resources?&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;Answer below ...&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;i&gt;Answer 1&lt;/i&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;It's because of a combination of problems.&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;Firstly, there are front-end tools that will not optimize their SQL to take account of situations where an aggregation of a metric is not required. A metric called "Transaction Qty" will commonly be defined as SUM(MASTER.TX_QTY) and will always be included in queries in the following way:&lt;/p&gt;  &lt;pre&gt;select&lt;br /&gt;transaction_cd,&lt;br /&gt;sum(tx_qty)&lt;br /&gt;from&lt;br /&gt;master&lt;br /&gt;where&lt;br /&gt;tx_timestamp between to_date('01-jan-2005')&lt;br /&gt;                 and to_date('02-jan-2005') and&lt;br /&gt;product_cd   = 3&lt;br /&gt;group by&lt;br /&gt;transaction_cd&lt;br /&gt;/&lt;/pre&gt; &lt;p style="margin-bottom: 0in;"&gt; The front end tool will not recognise that when the primary key of the MASTER fact table is also selected then it is sufficient (and more efficient) to:&lt;/p&gt;  &lt;pre&gt;select&lt;br /&gt;transaction_cd,&lt;br /&gt;tx_qty&lt;br /&gt;from&lt;br /&gt;master&lt;br /&gt;where&lt;br /&gt;tx_timestamp between to_date('01-jan-2005')&lt;br /&gt;                 and to_date('02-jan-2005') and&lt;br /&gt;product_cd   = 3&lt;br /&gt;/&lt;/pre&gt; &lt;p style="margin-bottom: 0in;"&gt; Now theoretically there is an opportunity for the Oracle optimizer to step in here and rescue us, but unfortunately it does not.&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;Here's a full demonstration script:&lt;/p&gt;  &lt;pre&gt;drop table master;&lt;br /&gt;drop materialized view master_mv1;&lt;br /&gt;&lt;br /&gt;create table master&lt;br /&gt;(&lt;br /&gt;transaction_cd not null,&lt;br /&gt;location_cd    not null,&lt;br /&gt;tx_timestamp   not null,&lt;br /&gt;product_cd     not null,&lt;br /&gt;tx_qty         not null,&lt;br /&gt;tx_cst         not null&lt;br /&gt;)&lt;br /&gt;pctfree 0&lt;br /&gt;nologging&lt;br /&gt;as&lt;br /&gt;select&lt;br /&gt;rownum,&lt;br /&gt;trunc(dbms_random.value(1,10)),&lt;br /&gt;to_date('01-jan-2005','DD-Mon-YYYY')&lt;br /&gt;   + dbms_random.value(0,30),&lt;br /&gt;trunc(dbms_random.value(1,10000)),&lt;br /&gt;trunc(dbms_random.value(1,10)),&lt;br /&gt;trunc(dbms_random.value(1,100),2)&lt;br /&gt;from&lt;br /&gt;dual&lt;br /&gt;connect by&lt;br /&gt;1=1 and&lt;br /&gt;level &lt; ownname     =""&gt; user,&lt;br /&gt;   tabname     =&gt; 'master',&lt;br /&gt;   granularity =&gt; 'ALL');&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;create materialized view master_mv1&lt;br /&gt;nologging&lt;br /&gt;Using No Index&lt;br /&gt;Never Refresh&lt;br /&gt;Enable Query Rewrite&lt;br /&gt;As&lt;br /&gt;Select&lt;br /&gt;transaction_cd,&lt;br /&gt;location_cd,&lt;br /&gt;product_cd,&lt;br /&gt;tx_timestamp,&lt;br /&gt;sum(tx_qty) s_tx_qty,&lt;br /&gt;sum(tx_cst) s_tx_cst&lt;br /&gt;from&lt;br /&gt;master&lt;br /&gt;group by&lt;br /&gt;transaction_cd,&lt;br /&gt;location_cd,&lt;br /&gt;product_cd,&lt;br /&gt;tx_timestamp&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;begin&lt;br /&gt;dbms_stats.gather_table_stats(&lt;br /&gt;   ownname     =&gt; user,&lt;br /&gt;   tabname     =&gt; 'master_mv1',&lt;br /&gt;   granularity =&gt; 'ALL');&lt;br /&gt;end;&lt;br /&gt;/&lt;/pre&gt; &lt;p&gt; We can now compare the original and the rewritten queries and their execution plans:&lt;/p&gt;  &lt;pre&gt;explain plan for&lt;br /&gt;select /*+ norewrite */&lt;br /&gt;    transaction_cd,&lt;br /&gt;    sum(tx_qty)&lt;br /&gt;from   master&lt;br /&gt;where  product_cd   = 3&lt;br /&gt;group by transaction_cd;&lt;br /&gt;&lt;br /&gt;select * from table(dbms_xplan.display());&lt;br /&gt;-----------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation          | Name   | Rows  | Bytes | Cost (%CPU)| Time     |&lt;br /&gt;-----------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT   |        |   102 |  1224 |   792   (3)| 00:00:10 |&lt;br /&gt;|   1 |  SORT GROUP BY     |        |   102 |  1224 |   792   (3)| 00:00:10 |&lt;br /&gt;|*  2 |   TABLE ACCESS FULL| MASTER |   102 |  1224 |   791   (3)| 00:00:10 |&lt;br /&gt;-----------------------------------------------------------------------------&lt;br /&gt;explain plan for&lt;br /&gt;select transaction_cd,&lt;br /&gt;    sum(tx_qty)&lt;br /&gt;from   master&lt;br /&gt;where  product_cd   = 3&lt;br /&gt;group by transaction_cd;&lt;br /&gt;select * from table(dbms_xplan.display());&lt;br /&gt;-------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation                    | Name       | Rows  | Bytes | Cost (%CPU)| Time     |&lt;br /&gt;-------------------------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT             |            |   101 |  1212 |   874   (3)| 00:00:11 |&lt;br /&gt;|*  1 |  MAT_VIEW REWRITE ACCESS FULL| MASTER_MV1 |   101 |  1212 |   874   (3)| 00:00:11 |&lt;br /&gt;-------------------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;explain plan for&lt;br /&gt;select transaction_cd,&lt;br /&gt;    sum(tx_qty)&lt;br /&gt;from   master&lt;br /&gt;where  location_cd   = 3&lt;br /&gt;group by transaction_cd;&lt;br /&gt;&lt;br /&gt;select * from table(dbms_xplan.display());&lt;br /&gt;-------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation                    | Name       | Rows  | Bytes | Cost (%CPU)| Time     |&lt;br /&gt;-------------------------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT             |            |   111K|  1193K|   873   (3)| 00:00:11 |&lt;br /&gt;|*  1 |  MAT_VIEW REWRITE ACCESS FULL| MASTER_MV1 |   111K|  1193K|   873   (3)| 00:00:11 |&lt;br /&gt;-------------------------------------------------------------------------------------------&lt;/pre&gt; &lt;p&gt; Notice also that if we place a tempting index on the transaction_cd column of master_mv1 then we can get further benefits:&lt;/p&gt;  &lt;pre&gt;alter table master_mv1 add constraint xpk_master_mv1 primary key (transaction_cd)&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;explain plan for&lt;br /&gt;select /*+ norewrite */&lt;br /&gt;    transaction_cd,&lt;br /&gt;    sum(tx_qty)&lt;br /&gt;from   master&lt;br /&gt;where  transaction_cd   in (1,2,123456)&lt;br /&gt;group by transaction_cd;&lt;br /&gt;&lt;br /&gt;select * from table(dbms_xplan.display());&lt;br /&gt;--------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation                     | Name       | Rows  | Bytes | Cost (%CPU)| Time     |&lt;br /&gt;--------------------------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT              |            |     3 |    24 |     4   (0)| 00:00:01 |&lt;br /&gt;|   1 |  SORT GROUP BY NOSORT         |            |     3 |    24 |     4   (0)| 00:00:01 |&lt;br /&gt;|   2 |   INLIST ITERATOR             |            |       |       |            |          |&lt;br /&gt;|   3 |    TABLE ACCESS BY INDEX ROWID| MASTER     |     3 |    24 |     4   (0)| 00:00:01 |&lt;br /&gt;|*  4 |     INDEX RANGE SCAN          | XPK_MASTER |     3 |       |     3   (0)| 00:00:01 |&lt;br /&gt;--------------------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;explain plan for&lt;br /&gt;select transaction_cd,&lt;br /&gt;    sum(tx_qty)&lt;br /&gt;from   master&lt;br /&gt;where  transaction_cd   in (1,2,123456)&lt;br /&gt;group by transaction_cd;&lt;br /&gt;&lt;br /&gt;select * from table(dbms_xplan.display());&lt;br /&gt;---------------------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation                               | Name           | Rows  | Bytes | Cost (%CPU)| Time     |&lt;br /&gt;----------------------------------------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT                        |                |     3 |    24 |     4   (0)| 00:00:01 |&lt;br /&gt;|   1 |  INLIST ITERATOR                        |                |       |       |            |          |&lt;br /&gt;|   2 |   MAT_VIEW REWRITE ACCESS BY INDEX ROWID| MASTER_MV1     |     3 |    24 |     4   (0)| 00:00:01 |&lt;br /&gt;|*  3 |    INDEX RANGE SCAN                     | XPK_MASTER_MV1 |     3 |       |     3   (0)| 00:00:01 |&lt;br /&gt;----------------------------------------------------------------------------------------------------------&lt;/pre&gt; &lt;p&gt; Again, the sort group by phase is eliminated.&lt;/p&gt;  &lt;p&gt; &lt;b&gt;Answer 2:&lt;/b&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;Different groups of users may have different reporting priorities. Store managers will be applying filters such as "location_cd = 5", while product managers will be applying "product_cd = 123". Both of them would benefit from the physical clustering of similar values for the columns they usually apply filters to, through partitioning (and hence partition pruning) or through an insert of rows sorted by their favourite column, or maybe though clustering.&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;My bet would be on the master and the MV tables having different partitioning keys.&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;Now that's not the only way to "skin this cat" -- of course you might go down the path of composite partitioning. However that will give you a limited number of columns on which partition pruning is possible. For example with a multicolumn-range/list composite partitioning scheme on (A,B,C)/(D) you can get partition pruning for queries on the following combinations of predicated columns:&lt;/p&gt;  &lt;ul&gt; &lt;li&gt;&lt;p style="margin-bottom: 0in;"&gt;A&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0in;"&gt;AB&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0in;"&gt;ABC&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0in;"&gt;ABCD&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0in;"&gt;AD&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0in;"&gt;ABD&lt;/p&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p style="margin-bottom: 0in;"&gt;The following combinations do not benefit from partition pruning:&lt;/p&gt;  &lt;ul&gt; &lt;li&gt;&lt;p style="margin-bottom: 0in;"&gt;B&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0in;"&gt;C&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0in;"&gt;BD&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0in;"&gt;CD&lt;/p&gt;  &lt;/li&gt;&lt;li&gt;&lt;p style="margin-bottom: 0in;"&gt;BCD&lt;/p&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p style="margin-bottom: 0in;"&gt;It's actually possible though to benefit from partition pruning in those latter cases if a logically redundant predicate is placed on other columns ... for example if A had only distinct values of 'X','Y', and 'Z' then by including a predicate of:&lt;/p&gt;  &lt;pre&gt;A In ('X','Y','Z')&lt;/pre&gt; &lt;p style="margin-bottom: 0in;"&gt; ...then it is possible to extend the range of partition pruning ... erm ... well maybe I'll write another blog entry on that, but as you can see it's a little bit tricky and still requires some upfront planning.&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;So does the query rewrite costing take account of differences in partitioning pruning between a master table and it's materialized views?&lt;/p&gt;  &lt;pre&gt;drop table master;&lt;br /&gt;drop materialized view master_mv1;&lt;br /&gt;&lt;br /&gt;create table master&lt;br /&gt;(&lt;br /&gt;transaction_cd not null,&lt;br /&gt;location_cd    not null,&lt;br /&gt;tx_timestamp   not null,&lt;br /&gt;product_cd     not null,&lt;br /&gt;tx_qty         not null,&lt;br /&gt;tx_cst         not null&lt;br /&gt;)&lt;br /&gt;partition by list (location_cd)&lt;br /&gt;(&lt;br /&gt;partition p01 values (1),&lt;br /&gt;partition p02 values (2),&lt;br /&gt;partition p03 values (3),&lt;br /&gt;partition p04 values (4),&lt;br /&gt;partition p05 values (5),&lt;br /&gt;partition p06 values (6),&lt;br /&gt;partition p07 values (7),&lt;br /&gt;partition p08 values (8),&lt;br /&gt;partition p09 values (9),&lt;br /&gt;partition p10 values (10)&lt;br /&gt;)&lt;br /&gt;pctfree 0&lt;br /&gt;nologging&lt;br /&gt;as&lt;br /&gt;select&lt;br /&gt;rownum,&lt;br /&gt;trunc(dbms_random.value(1,10)),&lt;br /&gt;to_date('01-jan-2005','DD-Mon-YYYY')&lt;br /&gt;  + dbms_random.value(0,30),&lt;br /&gt;trunc(dbms_random.value(1,10000)),&lt;br /&gt;trunc(dbms_random.value(1,10)),&lt;br /&gt;trunc(dbms_random.value(1,100),2)&lt;br /&gt;from&lt;br /&gt;dual&lt;br /&gt;connect by&lt;br /&gt;1=1 and&lt;br /&gt;level &lt; ownname     =""&gt; user,&lt;br /&gt;  tabname     =&gt; 'master',&lt;br /&gt;  granularity =&gt; 'ALL');&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;create materialized view master_mv1&lt;br /&gt;partition by hash (product_cd)&lt;br /&gt;partitions 256&lt;br /&gt;compress nologging&lt;br /&gt;Using No Index&lt;br /&gt;Never Refresh&lt;br /&gt;Enable Query Rewrite&lt;br /&gt;As&lt;br /&gt;Select&lt;br /&gt;transaction_cd,&lt;br /&gt;location_cd,&lt;br /&gt;product_cd,&lt;br /&gt;tx_timestamp,&lt;br /&gt;sum(tx_qty) s_tx_qty,&lt;br /&gt;sum(tx_cst) s_tx_cst&lt;br /&gt;from&lt;br /&gt;master&lt;br /&gt;group by&lt;br /&gt;transaction_cd,&lt;br /&gt;location_cd,&lt;br /&gt;product_cd,&lt;br /&gt;tx_timestamp&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;begin&lt;br /&gt;dbms_stats.gather_table_stats(&lt;br /&gt;  ownname     =&gt; user,&lt;br /&gt;  tabname     =&gt; 'master_mv1',&lt;br /&gt;  granularity =&gt; 'ALL');&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;explain plan for&lt;br /&gt;select   transaction_cd,&lt;br /&gt;      sum(tx_qty)&lt;br /&gt;from     master&lt;br /&gt;where    product_cd   = 3&lt;br /&gt;group by transaction_cd;&lt;br /&gt;&lt;br /&gt;select * from table(dbms_xplan.display());&lt;br /&gt;&lt;br /&gt;explain plan for&lt;br /&gt;select   transaction_cd,&lt;br /&gt;      sum(tx_qty)&lt;br /&gt;from     master&lt;br /&gt;where    location_cd   = 3&lt;br /&gt;group by transaction_cd;&lt;br /&gt;&lt;br /&gt;select * from table(dbms_xplan.display());&lt;/pre&gt; &lt;p style="margin-bottom: 0in;"&gt; Here are the execution plans:&lt;/p&gt;  &lt;pre&gt;-------------------------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation                      | Name       | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |&lt;br /&gt;-------------------------------------------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT               |            |     9 |   108 |     4  (25)| 00:00:01 |       |       |&lt;br /&gt;|   1 |  SORT GROUP BY                 |            |     9 |   108 |     4  (25)| 00:00:01 |       |       |&lt;br /&gt;|   2 |   PARTITION HASH SINGLE        |            |     9 |   108 |     3   (0)| 00:00:01 |    36 |    36 |&lt;br /&gt;|*  3 |    MAT_VIEW REWRITE ACCESS FULL| MASTER_MV1 |     9 |   108 |     3   (0)| 00:00:01 |    36 |    36 |&lt;br /&gt;-------------------------------------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;---------------------------------------------------------------------------------------------------------&lt;br /&gt;| Id  | Operation              | Name   | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |&lt;br /&gt;---------------------------------------------------------------------------------------------------------&lt;br /&gt;|   0 | SELECT STATEMENT       |        | 11040 |   118K|       |    63   (4)| 00:00:01 |       |       |&lt;br /&gt;|   1 |  SORT GROUP BY         |        | 11040 |   118K|   536K|    63   (4)| 00:00:01 |       |       |&lt;br /&gt;|   2 |   PARTITION LIST SINGLE|        | 11040 |   118K|       |    11   (0)| 00:00:01 |     3 |     3 |&lt;br /&gt;|   3 |    TABLE ACCESS FULL   | MASTER | 11040 |   118K|       |    11   (0)| 00:00:01 |     3 |     3 |&lt;br /&gt;---------------------------------------------------------------------------------------------------------&lt;br /&gt;&lt;/pre&gt; &lt;p style="margin-bottom: 0in;"&gt; We see here that the query is rewritten to take advantage of the different partitioning scheme of the materialized view. This simple case would have been a good candidate for a composite partitioning scheme of course.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;   &lt;p style="margin-bottom: 0in;"&gt;&lt;i&gt;&lt;b&gt;The Cost Of Maintaining Redundant Materialized Views&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;   &lt;p style="margin-bottom: 0in;"&gt;So what is the cost to the system of providing this materialized view? Well if we're smart about how we maintain it then there is very little cost indeed. After all, we know that we don't have to aggregate the master data in order to populate the materialized view's table so I don't see why we would choose to do so.&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;In this &lt;a href="http://oraclesponge.blogspot.com/2005/11/reducing-work-of-refreshing-multiple.html"&gt;previous blog&lt;/a&gt; I showed how there can be benefits to maintaining a materialized view manually, rather than through the internal refresh procedure. This redundant MV is an excellent example of a situation that benefits from such an approach, because the MV data is exactly the same as the master data. So instead of inserting the master table data and then refreshing the MV we can insert into both tables at the same time. As I noted before, the MV data can be maintained manually through either the partition exchange mechanism or by dropping the MV (if it is built on a predefined table) and directly inserting into it. In the latter case we could even use the multitable insert syntax that Oracle so thoughtfully provides to insert into both the master and the MV tables simultaneously, giving us the benefit of a single transaction.&lt;/p&gt;   &lt;p style="margin-bottom: 0in;"&gt;&lt;b&gt;&lt;i&gt;Summary&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;So there we have it. Materialized views that are redundant in terms of data but which can provide interesting benefits in the report query phase.&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;Would I do such a thing myself? Maybe, maybe not. I don't believe that there ought to be qualms about the extra storage requirement because by the time you have used up half the capacity of todays hard drives you have already run out of bandwidth. I haven't worked in an environment where I have felt comfortable in implementing such a scheme, but I could see that I might. I can imagine a related situation where I would create a materialized view on a subset of the master table's columns in order to provide a skinny table (possibly with different partitioning scheme), in order to get the benefits of reduced i/o for scans of large number of rows and/or to leverage the optimizer's abandonment of the SORT GROUP BY phase when reporting on a primary key column.&lt;/p&gt;  &lt;p style="margin-bottom: 0in;"&gt;Regardless of the practicality, I think that it serves as a nice demonstration of the power of query rewrite.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113277599553123549?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113277599553123549/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113277599553123549' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113277599553123549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113277599553123549'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/mysterious-benefit-of-completely.html' title='The Mysterious Benefit Of Completely Redundant Materialized Views'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113384429125492707</id><published>2005-12-05T21:43:00.000-07:00</published><updated>2005-12-05T21:44:57.266-07:00</updated><title type='text'>Dimensions Without Dimension Tables</title><content type='html'>Mike Ault has blogged on the subject &lt;a href="http://mikerault.blogspot.com/2005/11/becoming-non-dimensional.html"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113384429125492707?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113384429125492707/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113384429125492707' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113384429125492707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113384429125492707'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/dimensions-without-dimension-tables.html' title='Dimensions Without Dimension Tables'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113346186188598773</id><published>2005-12-01T11:16:00.000-07:00</published><updated>2005-12-01T11:31:01.926-07:00</updated><title type='text'>Oracle Documentation Slow?</title><content type='html'>Is it just me or is the Oracle documentation site very slow right now? I keep getting timeouts on searching.&lt;br /&gt;&lt;br /&gt;I feel like someone is stepping on my oxygen pipe when that happens.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113346186188598773?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113346186188598773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113346186188598773' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113346186188598773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113346186188598773'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/oracle-documentation-slow.html' title='Oracle Documentation Slow?'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113345038185348111</id><published>2005-12-01T08:09:00.000-07:00</published><updated>2005-12-01T08:19:41.896-07:00</updated><title type='text'>Antivirus and Firewall Software Change</title><content type='html'>Norton is out, and AVS is in.&lt;br /&gt;&lt;br /&gt;Norton has been killing my internet connection for a little while apparantly, but I only just found out that it was responsible when I noticed ccproxy.exe consuming 1.5Gb of memory and growing ... it's the kind of thing you tend to notice on a machine with 1.5Gb of physical memory plus Oracle EE 10gR1 running on it. I had to keep restarting the Symantec Netwrok Proxy service to restore the connection. "Bye-bye!"&lt;br /&gt;&lt;br /&gt;So it turns out that not only does AVS have all the required credentials but it's user interface is also not nearly as funky as Norton's. It appears to do all the same stuff, plus it registers itself with Windows XP Security Center (which Norton never managed to do). The firewall part does everything I need as well.&lt;br /&gt;&lt;br /&gt;Oh, and it's a darned sight cheaper as well -- the anti-virus part is free for home users, and AVG + Firewall Edition is a snip at $48.95 for a &lt;span style="font-style: italic;"&gt;two year&lt;/span&gt; license.&lt;br /&gt;&lt;br /&gt;Here you go: http://www.grisoft.com&lt;br /&gt;&lt;br /&gt;(Their website is also much easier to use than Symantec's as well)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113345038185348111?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113345038185348111/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113345038185348111' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113345038185348111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113345038185348111'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/12/antivirus-and-firewall-software-change.html' title='Antivirus and Firewall Software Change'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112913169286787027</id><published>2005-11-23T06:00:00.000-07:00</published><updated>2005-12-09T13:19:52.366-07:00</updated><title type='text'>Optimizing Materialized Views Part III: Manual Refresh Mechanisms</title><content type='html'>So, back on the subject of fast-refreshing multiple materialized views.&lt;br /&gt;&lt;br /&gt;Reviewing my previous comments on this, I think it's time for some clarification. I wrote before that I prefer to consider that fast refresh is based on the materialized view log rather than the master table itself, but as I also wrote in a followup this is not actually the case when you load a master table using direct path inserts. In fact the materialized view log is not touched in this circumstance and instead the logging takes place in the ALL_SUM_DELTA system view. So from the view point of the refresh process itself you can consider the materialized view log to be redundant. This doesn't mean that you can do away with it, however. There is no mechanism in Oracle for saying that you want a materialized view to be fast refreshable based only on direct path inserts and that the MV log is never going to be used.&lt;br /&gt;&lt;br /&gt;In fact you might want to go so far as to ensure that it really is redundant by preventing inserts into it, since these would be an indication that conventional path insert is being used. A couple of mechanisms for this spring to mind, such as placing the log in a readonly tablespace, or placing an error-raising insert trigger on it. This would thereby prevent anything other than a direct path insert into the master table, including deletes and updates -- considering the performance disparity between conventional and direct path change logging and subsequent fast refresh I would be inclined to go ahead with such a plan.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Refresh Mechanism Following Direct-Path Insert&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So given that you have inserted data to the master table in direct path mode, what is the refresh mechanism for the materialized views? Looking at a SQL trace file tells us that a MERGE statement is used. Here is a prettified example derived from the script used &lt;a href="http://oraclesponge.blogspot.com/2005/09/reducing-work-of-refreshing-multiple_15.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Merge Into DAVE.MASTER_MV1 SNA$&lt;br /&gt;Using&lt;br /&gt;(&lt;br /&gt;Select  /*+  &lt;a href="http://www.oracle.com/technology/products/manageability/database/pdf/ow04/1238_lewis.pdf"&gt;Opt_Estimate&lt;/a&gt;(Query_Block Max=1000)   */&lt;br /&gt;DLT$0.LOCATION_CD                          GB0,&lt;br /&gt;Trunc(DLT$0.TX_TIMESTAMP,'MM')             GB1,&lt;br /&gt;Sum(1)                                     D0,&lt;br /&gt;Nvl(Sum(1*(DLT$0.TX_CST)), 0)              D1,&lt;br /&gt;Sum(1* Decode((DLT$0.TX_CST), Null, 0, 1)) H1,&lt;br /&gt;Nvl(Sum(1*(DLT$0.TX_QTY)), 0)              D2,&lt;br /&gt;Sum(1* Decode((DLT$0.TX_QTY), Null, 0, 1)) H2&lt;br /&gt;From     (&lt;br /&gt;Select  /*+ &lt;a href="http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:3779680732446#15752466976248"&gt;Cardinality&lt;/a&gt;(16800) &lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10739/ds_appdev.htm#sthref3895"&gt;No_Merge&lt;/a&gt; &lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10739/ds_appdev.htm#sthref3895"&gt;No_Merge&lt;/a&gt;(LL$) &lt;a href="http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96533/hintsref.htm#5104"&gt;Rowid&lt;/a&gt;(MAS$)&lt;br /&gt;          &lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10752/hintsref.htm#5555"&gt;Ordered&lt;/a&gt; &lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10752/hintsref.htm#5555"&gt;Use_Nl&lt;/a&gt;(MAS$) &lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10752/hintsref.htm#PFGRF50803"&gt;No_Index&lt;/a&gt;(MAS$) &lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10752/hintsref.htm#PFGRF50803"&gt;PQ_Distribute&lt;/a&gt;(MAS$,Random,None) */&lt;br /&gt;     MAS$.ROWID RID$  ,&lt;br /&gt;     MAS$.TX_TIMESTAMP,&lt;br /&gt;     MAS$.LOCATION_CD ,&lt;br /&gt;     MAS$.TX_CST      ,&lt;br /&gt;     MAS$.TX_QTY&lt;br /&gt;From   ALL_SUMDELTA LL$,&lt;br /&gt;     DAVE.MASTER MAS$&lt;br /&gt;Where  LL$.TABLEOBJ# = 256646 And&lt;br /&gt;     LL$.TIMESTAMP &gt; :1     And&lt;br /&gt;     MAS$.ROWID    Between LL$.LOWROWID&lt;br /&gt;                       And LL$.HIGHROWID&lt;br /&gt;) As Of Snapshot (:2)  DLT$0&lt;br /&gt;Group By DLT$0.LOCATION_CD,&lt;br /&gt;Trunc(DLT$0.TX_TIMESTAMP,'MM')&lt;br /&gt;)AV$&lt;br /&gt;On (&lt;br /&gt;&lt;a href="http://groups.google.com/groups?hl=en&amp;lr=&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;ie=UTF-8&amp;oe=UTF-8&amp;amp;threadm=bpsipq%24sas%241%248302bc10%40news.demon.co.uk&amp;rnum=1&amp;amp;prev=/groups%3Fq%3Dsys_op_map_nonnull%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3DUTF-8%26selm%3Dbpsipq%2524sas%25241%25248302bc10%2540news.demon.co.uk%26rnum%3D1"&gt;Sys_Op_Map_NonNull&lt;/a&gt;(SNA$.LOCATION_CD) = Sys_Op_Map_NonNull(AV$.GB0) And&lt;br /&gt;Sys_Op_Map_NonNull(SNA$.TX_MONTH)    = Sys_Op_Map_NonNull(AV$.GB1)&lt;br /&gt;)&lt;br /&gt;When Matched Then&lt;br /&gt;Update  Set SNA$.C_STAR   = SNA$.C_STAR+AV$.D0,&lt;br /&gt; SNA$.S_TX_CST = DECODE(SNA$.S_TX_CST,&lt;br /&gt;                        Null, Decode(AV$.H1, 0, Null, AV$.D1),&lt;br /&gt;                              (SNA$.S_TX_CST + AV$.D1)),&lt;br /&gt; SNA$.S_TX_QTY = Decode(SNA$.S_TX_QTY,&lt;br /&gt;                        Null, Decode(AV$.H2,0,Null,AV$.D2),&lt;br /&gt;                              (SNA$.S_TX_QTY + AV$.D2))&lt;br /&gt;When Not Matched Then&lt;br /&gt;Insert (SNA$.LOCATION_CD,&lt;br /&gt;SNA$.TX_MONTH,&lt;br /&gt;SNA$.C_STAR,&lt;br /&gt;SNA$.S_TX_CST,&lt;br /&gt;SNA$.S_TX_QTY)&lt;br /&gt;Values (AV$.GB0,&lt;br /&gt;AV$.GB1,&lt;br /&gt;AV$.D0,&lt;br /&gt;Decode(AV$.H1,0,Null,AV$.D1),&lt;br /&gt;Decode(AV$.H2,0,Null,AV$.D2))&lt;br /&gt;&lt;/pre&gt;One of the characteristics to note is the absence of an APPEND hint in the merge statement, and to me this implies the following:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;New rows will be inserted through the conventional path. No direct path for you!&lt;/li&gt;   &lt;li&gt;Data segment compression on the MV base table will not be leveraged.&lt;/li&gt;   &lt;li&gt;If a fast refreshable MV is referencing MV1 as its master table then the change logging will be performed in the MV1 materialized view log, not through the SUM_DELTA mechanism&lt;/li&gt; &lt;/ol&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Optimizing MV Refresh By Avoiding MERGE&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Another issue to note is simply that a single merge statement is used instead of an insert and an update. It is not inconcievable that you have a situation where the new data added to a fact table does not require modification of existing rows in one or more materialized views. If the materialized view groups by "Column A" and each load cycle on the fact table contains values of "Column A" that never appear in any other load cycle then this would be the case, and this might be either implicit or explicit in your data loading application.&lt;br /&gt;&lt;br /&gt;The distinction here between implicit and explicit refers to whether the uniqueness of "Column A" to a particular load cycle is a deliberate design feature or whether it is more by happenstance or business requirements. An example of an explicit situation would be where you use a unique "load cycle code" as part of your ETL procedure (not a bad idea in itself), assigning a new value to each load and pushing this into one or more MV's. An example of an implicit situation might be where each load cycle operates on a granularity of fact table data that is repeated in the materialized view, such as where you load a complete day of transactions represented by a contiguous range of "TRANSACTION_TIME" (midnight-to-midnight) and the materialized view contains an expression such as:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;Trunc(TRANSACTION_TIME,'MI')&lt;/li&gt;   &lt;li&gt;Trunc(TRANSACTION_TIME,'HH')&lt;/li&gt;   &lt;li&gt;Trunc(TRANSACTION_TIME,'D')&lt;/li&gt; &lt;/ul&gt; In such a circumstance it is conceivable that it would be more efficient to manage the materialized view aggregation ourself than to leave it to the RDBMS, because using an insert allows us the following potential advantages:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;We avoid a potentially expensive join to the MV.&lt;/li&gt;   &lt;li&gt;A direct path write allows us to minimize logging.&lt;/li&gt;   &lt;li&gt;A direct path write allows us to use data segment compression.&lt;/li&gt;   &lt;li&gt;We can enforce a sort order in the materialized view data, potentially improving report query performance&lt;/li&gt; &lt;/ol&gt; I predict that this last issue will become more important in 10gR2 as the new hash-based aggregation algorithm replaces the current sort-based method, and the likelihood that GROUP BY returns a value-clustered result set is reduced.&lt;br /&gt;&lt;br /&gt;However the tricky part of such an operation is in modifying the materialized view's data, which is not allowed through DML.&lt;br /&gt;&lt;pre&gt;SQL&gt; insert into master_mv1&lt;br /&gt;2  select&lt;br /&gt;3     location_cd,&lt;br /&gt;4     trunc(tx_timestamp,'MM') tx_month,&lt;br /&gt;5     sum(tx_qty) s_tx_qty,&lt;br /&gt;6     sum(tx_cst) s_tx_cst,&lt;br /&gt;7     count(*)    c_star&lt;br /&gt;8  from&lt;br /&gt;9     master&lt;br /&gt;10  group by&lt;br /&gt;11     location_cd,&lt;br /&gt;12     trunc(tx_timestamp,'MM')&lt;br /&gt;13  /&lt;br /&gt;insert into master_mv1&lt;br /&gt;*&lt;br /&gt;ERROR at line 1:&lt;br /&gt;ORA-01732: data manipulation operation not legal on this view&lt;/pre&gt;For the experienced data warehouse developer an obvious method for bypassing such a limitation is to use a partition exchange operation, so let us construct a test case.&lt;br /&gt;&lt;br /&gt;In this script we load a fact table upon which are based two materialized views, one of which is &lt;span style="font-style: italic;"&gt;refresh on demand&lt;/span&gt; and the other of which is &lt;span style="font-style: italic;"&gt;never refresh&lt;/span&gt;. The latter will be manually refreshed using a direct path insert into a non-partitioned table followed by a partition exchange without validation. To avoid either of the refresh processes benefiting from buffer caching by the other, the buffer cache will be flushed.&lt;br /&gt;&lt;pre&gt;drop table master;&lt;br /&gt;drop table master_test_data;&lt;br /&gt;drop table master_mv1_exch;&lt;br /&gt;drop materialized view master_mv1;&lt;br /&gt;drop materialized view master_mv2;&lt;br /&gt;&lt;br /&gt;create table master&lt;br /&gt;(&lt;br /&gt;location_cd  number not null,&lt;br /&gt;tx_timestamp date   not null,&lt;br /&gt;product_cd   number not null,&lt;br /&gt;tx_qty       number not null,&lt;br /&gt;tx_cst       number not null&lt;br /&gt;)&lt;br /&gt;pctfree 0&lt;br /&gt;nologging&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;create materialized view log on master&lt;br /&gt;with rowid&lt;br /&gt;(&lt;br /&gt;location_cd,&lt;br /&gt;tx_timestamp,&lt;br /&gt;product_cd,&lt;br /&gt;tx_qty,&lt;br /&gt;tx_cst&lt;br /&gt;)&lt;br /&gt;including new values&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;create materialized view master_mv1&lt;br /&gt;compress nologging&lt;br /&gt;Partition By List (TX_MONTH)&lt;br /&gt;(&lt;br /&gt;Partition Y2005M01 Values (to_date('01-jan-2005'))&lt;br /&gt;)&lt;br /&gt;Using No Index&lt;br /&gt;Never Refresh&lt;br /&gt;Enable Query Rewrite&lt;br /&gt;As&lt;br /&gt;Select&lt;br /&gt;product_cd,&lt;br /&gt;trunc(tx_timestamp,'MM') tx_month,&lt;br /&gt;sum(tx_qty) s_tx_qty,&lt;br /&gt;sum(tx_cst) s_tx_cst,&lt;br /&gt;count(*)    c_star&lt;br /&gt;from&lt;br /&gt;master&lt;br /&gt;group by&lt;br /&gt;product_cd,&lt;br /&gt;trunc(tx_timestamp,'MM')&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;create table master_mv1_exch&lt;br /&gt;compress nologging&lt;br /&gt;as&lt;br /&gt;select *&lt;br /&gt;from   master_mv1&lt;br /&gt;where  1=0&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;create materialized view master_mv2&lt;br /&gt;compress nologging&lt;br /&gt;Partition By List (TX_MONTH)&lt;br /&gt;(&lt;br /&gt;Partition Y2005M01 Values (to_date('01-jan-2005'))&lt;br /&gt;)&lt;br /&gt;Using No Index&lt;br /&gt;Refresh Fast On Demand&lt;br /&gt;Enable Query Rewrite&lt;br /&gt;As&lt;br /&gt;Select&lt;br /&gt;product_cd,&lt;br /&gt;trunc(tx_timestamp,'MM') tx_month,&lt;br /&gt;sum(tx_qty) s_tx_qty,&lt;br /&gt;sum(tx_cst) s_tx_cst,&lt;br /&gt;count(*)    c_star&lt;br /&gt;from&lt;br /&gt;master&lt;br /&gt;group by&lt;br /&gt;product_cd,&lt;br /&gt;trunc(tx_timestamp,'MM')&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;create table master_test_data&lt;br /&gt;(&lt;br /&gt;location_cd  not null,&lt;br /&gt;tx_timestamp not null,&lt;br /&gt;product_cd   not null,&lt;br /&gt;tx_qty       not null,&lt;br /&gt;tx_cst       not null&lt;br /&gt;)&lt;br /&gt;pctfree 0&lt;br /&gt;nologging&lt;br /&gt;as&lt;br /&gt;select&lt;br /&gt;trunc(dbms_random.value(1,10)),&lt;br /&gt;to_date('01-jan-2005','DD-Mon-YYYY')&lt;br /&gt;+ dbms_random.value(0,30),&lt;br /&gt;trunc(dbms_random.value(1,1000)),&lt;br /&gt;trunc(dbms_random.value(1,10)),&lt;br /&gt;trunc(dbms_random.value(1,100),2)&lt;br /&gt;from&lt;br /&gt;dual&lt;br /&gt;connect by&lt;br /&gt;1=1 and&lt;br /&gt;level &lt; list      =""&gt; 'MASTER_MV2',&lt;br /&gt;method    =&gt; 'F');&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;exit&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;From the wall-clock timing of the queries the manual refresh is superior with its three stages of insert, partition exchange and "consider fresh" completing in 5.08 seconds (4.75+0.15+0.18), representing 66% of the merge-based MV refresh time of 7.65 seconds.&lt;br /&gt;&lt;br /&gt;Tkprof extracted the following details from the trace file&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;********************************************************************************&lt;br /&gt;&lt;br /&gt;Insert /*+ append */ Into master_mv1_exch&lt;br /&gt;Select&lt;br /&gt;product_cd,&lt;br /&gt;trunc(tx_timestamp,'MM') tx_month,&lt;br /&gt;sum(tx_qty) s_tx_qty,&lt;br /&gt;sum(tx_cst) s_tx_cst,&lt;br /&gt;count(*)    c_star&lt;br /&gt;from&lt;br /&gt;master&lt;br /&gt;group by&lt;br /&gt;product_cd,&lt;br /&gt;trunc(tx_timestamp,'MM')&lt;br /&gt;&lt;br /&gt;call     count       cpu    elapsed       disk      query    current        rows&lt;br /&gt;------- ------  -------- ---------- ---------- ---------- ----------  ----------&lt;br /&gt;Parse        1      0.03       0.05          2        344          3           0&lt;br /&gt;Execute      1      2.89       3.78       1927       3404        110        9999&lt;br /&gt;Fetch        0      0.00       0.00          0          0          0           0&lt;br /&gt;------- ------  -------- ---------- ---------- ---------- ----------  ----------&lt;br /&gt;total        2      2.92       3.83       1929       3748        113        9999&lt;br /&gt;&lt;br /&gt;Misses in library cache during parse: 1&lt;br /&gt;Optimizer mode: ALL_ROWS&lt;br /&gt;Parsing user id: 40&lt;br /&gt;&lt;br /&gt;Rows     Row Source Operation&lt;br /&gt;-------  ---------------------------------------------------&lt;br /&gt;1  LOAD AS SELECT  (cr=3404 pr=1927 pw=27 time=3785583 us)&lt;br /&gt;9999   SORT GROUP BY (cr=3365 pr=1914 pw=0 time=3652049 us)&lt;br /&gt;1000000    TABLE ACCESS FULL MASTER (cr=3365 pr=1914 pw=0 time=4008780 us)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Elapsed times include waiting on following events:&lt;br /&gt;Event waited on                             Times   Max. Wait  Total Waited&lt;br /&gt;----------------------------------------   Waited  ----------  ------------&lt;br /&gt;db file sequential read                        11        0.01          0.05&lt;br /&gt;control file sequential read                    4        0.00          0.00&lt;br /&gt;db file scattered read                         70        0.18          0.73&lt;br /&gt;direct path write                               5        0.00          0.00&lt;br /&gt;SQL*Net message to client                       1        0.00          0.00&lt;br /&gt;SQL*Net message from client                     1        0.00          0.00&lt;br /&gt;********************************************************************************&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;********************************************************************************&lt;br /&gt;&lt;br /&gt;MERGE INTO "DAVE"."MASTER_MV2" "SNA$" USING (SELECT   /*+&lt;br /&gt;OPT_ESTIMATE(QUERY_BLOCK MAX=1000)   */ "DLT$0"."PRODUCT_CD" "GB0",&lt;br /&gt;TRUNC("DLT$0"."TX_TIMESTAMP",'MM') "GB1", SUM(1) "D0", NVL(SUM(1*&lt;br /&gt;("DLT$0"."TX_CST")), 0) "D1", SUM(1* DECODE(("DLT$0"."TX_CST"), NULL, 0, 1))&lt;br /&gt;"H1", NVL(SUM(1* ("DLT$0"."TX_QTY")), 0) "D2", SUM(1*&lt;br /&gt;DECODE(("DLT$0"."TX_QTY"), NULL, 0, 1)) "H2" FROM (SELECT  /*+ CARDINALITY(&lt;br /&gt;335800) NO_MERGE NO_MERGE(LL$) ROWID(MAS$) ORDERED USE_NL(MAS$)&lt;br /&gt;NO_INDEX(MAS$) PQ_DISTRIBUTE(MAS$,RANDOM,NONE) */  "MAS$"."ROWID" RID$  ,&lt;br /&gt;"MAS$"."TX_TIMESTAMP", "MAS$"."PRODUCT_CD", "MAS$"."TX_CST",&lt;br /&gt;"MAS$"."TX_QTY"  FROM ALL_SUMDELTA "LL$", "DAVE"."MASTER" "MAS$" WHERE&lt;br /&gt;LL$.TABLEOBJ# = 257149 AND "LL$".TIMESTAMP &gt; :1 AND  "MAS$".ROWID BETWEEN&lt;br /&gt;"LL$".LOWROWID AND  "LL$".HIGHROWID ) AS OF SNAPSHOT (:2)  "DLT$0"  GROUP&lt;br /&gt;BY "DLT$0"."PRODUCT_CD",TRUNC("DLT$0"."TX_TIMESTAMP",'MM'))"AV$" ON&lt;br /&gt;(SYS_OP_MAP_NONNULL("SNA$"."PRODUCT_CD")=SYS_OP_MAP_NONNULL("AV$"."GB0")&lt;br /&gt;AND SYS_OP_MAP_NONNULL("SNA$"."TX_MONTH")=SYS_OP_MAP_NONNULL("AV$"."GB1"))&lt;br /&gt;WHEN MATCHED THEN UPDATE  SET "SNA$"."C_STAR"="SNA$"."C_STAR"+"AV$"."D0",&lt;br /&gt;"SNA$"."S_TX_CST"=DECODE("SNA$"."S_TX_CST", NULL, DECODE("AV$"."H1", 0,&lt;br /&gt;NULL, "AV$"."D1"), ("SNA$"."S_TX_CST" + "AV$"."D1")), "SNA$"."S_TX_QTY"=&lt;br /&gt;DECODE("SNA$"."S_TX_QTY", NULL, DECODE("AV$"."H2", 0, NULL, "AV$"."D2"),&lt;br /&gt;("SNA$"."S_TX_QTY" + "AV$"."D2")) WHEN NOT MATCHED THEN INSERT&lt;br /&gt;("SNA$"."PRODUCT_CD", "SNA$"."TX_MONTH", "SNA$"."C_STAR", "SNA$"."S_TX_CST",&lt;br /&gt;"SNA$"."S_TX_QTY") VALUES ( "AV$"."GB0", "AV$"."GB1", "AV$"."D0", DECODE&lt;br /&gt;("AV$"."H1", 0, NULL, "AV$"."D1"), DECODE ("AV$"."H2", 0, NULL, "AV$"."D2"))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;call     count       cpu    elapsed       disk      query    current        rows&lt;br /&gt;------- ------  -------- ---------- ---------- ---------- ----------  ----------&lt;br /&gt;Parse        1      0.01       0.01          0          0          4           0&lt;br /&gt;Execute      1      6.04       6.66       1922       3760      10640        9999&lt;br /&gt;Fetch        0      0.00       0.00          0          0          0           0&lt;br /&gt;------- ------  -------- ---------- ---------- ---------- ----------  ----------&lt;br /&gt;total        2      6.06       6.68       1922       3760      10644        9999&lt;br /&gt;&lt;br /&gt;Misses in library cache during parse: 1&lt;br /&gt;Misses in library cache during execute: 1&lt;br /&gt;Optimizer mode: ALL_ROWS&lt;br /&gt;Parsing user id: 40     (recursive depth: 1)&lt;br /&gt;&lt;br /&gt;Rows     Row Source Operation&lt;br /&gt;-------  ---------------------------------------------------&lt;br /&gt;2  MERGE  (cr=3811 pr=1925 pw=0 time=6662264 us)&lt;br /&gt;9999   VIEW  (cr=3682 pr=1914 pw=0 time=6556192 us)&lt;br /&gt;9999    HASH JOIN RIGHT OUTER (cr=3682 pr=1914 pw=0 time=6516189 us)&lt;br /&gt;0     PARTITION LIST SINGLE PARTITION: 1 1 (cr=3 pr=0 pw=0 time=92 us)&lt;br /&gt;0      MAT_VIEW ACCESS FULL MASTER_MV2 PARTITION: 1 1 (cr=3 pr=0 pw=0 time=73 us)&lt;br /&gt;9999     VIEW  (cr=3679 pr=1914 pw=0 time=6415840 us)&lt;br /&gt;9999      SORT GROUP BY (cr=3679 pr=1914 pw=0 time=6365838 us)&lt;br /&gt;1000000       VIEW  (cr=3679 pr=1914 pw=0 time=14006210 us)&lt;br /&gt;1000000        NESTED LOOPS  (cr=3679 pr=1914 pw=0 time=8006206 us)&lt;br /&gt;35         VIEW  (cr=76 pr=0 pw=0 time=4235 us)&lt;br /&gt;35          FILTER  (cr=76 pr=0 pw=0 time=4055 us)&lt;br /&gt;35           NESTED LOOPS  (cr=76 pr=0 pw=0 time=3802 us)&lt;br /&gt;35            NESTED LOOPS  (cr=4 pr=0 pw=0 time=755 us)&lt;br /&gt;1             TABLE ACCESS BY INDEX ROWID OBJ$ (cr=3 pr=0 pw=0 time=75 us)&lt;br /&gt;1              INDEX UNIQUE SCAN I_OBJ1 (cr=2 pr=0 pw=0 time=32 us)(object id 36)&lt;br /&gt;35             INDEX RANGE SCAN I_SUMDELTA$ (cr=1 pr=0 pw=0 time=472 us)(object id 161)&lt;br /&gt;35            TABLE ACCESS CLUSTER USER$ (cr=72 pr=0 pw=0 time=2556 us)&lt;br /&gt;35             INDEX UNIQUE SCAN I_USER# (cr=2 pr=0 pw=0 time=798 us)(object id 11)&lt;br /&gt;0           NESTED LOOPS  (cr=0 pr=0 pw=0 time=0 us)&lt;br /&gt;0            INDEX RANGE SCAN I_OBJAUTH1 (cr=0 pr=0 pw=0 time=0 us)(object id 107)&lt;br /&gt;0            FIXED TABLE FULL X$KZSRO (cr=0 pr=0 pw=0 time=0 us)&lt;br /&gt;0           FIXED TABLE FULL X$KZSPR (cr=0 pr=0 pw=0 time=0 us)&lt;br /&gt;1000000         TABLE ACCESS FULL MASTER (cr=3603 pr=1914 pw=0 time=3222833 us)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Elapsed times include waiting on following events:&lt;br /&gt;Event waited on                             Times   Max. Wait  Total Waited&lt;br /&gt;----------------------------------------   Waited  ----------  ------------&lt;br /&gt;db file sequential read                        10        0.00          0.03&lt;br /&gt;db file scattered read                         70        0.02          0.48&lt;br /&gt;log buffer space                               13        0.00          0.03&lt;br /&gt;********************************************************************************&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The difference in elapsed time between the two methods is almost entirely accounted for in CPU time, probably due to the joins required by the merge statement. You might also notice that I took the opportunity to make the tables NOLOGGING and COMPRESS.&lt;br /&gt;&lt;br /&gt;The methodology presented here for the manual refresh of the materialized view through a partition exchange is not the only one available, of course. Another choice might be to define the materialized view upon a prebuilt table, which allows the MV to be temporarily dropped so as to allow DML on the underlying table. The recreation of the MV definition is then a trivial issue in terms of database work required, and the only effect would be the temporary loss of the ability to rewrite queries against that MV. It would have the further advantage that indexes (or partitions thereof) on the materialized view table could be temporarily rendered unusable during the insert process so as to rebuild them in a nologging mode, without users being inconvenienced by "unusable index" errors.&lt;br /&gt;&lt;br /&gt;It would also be possible to split the manual refresh into more stages to reduce the period for which query rewrite is unavailable:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Aggregate master table to temporary table&lt;/li&gt;   &lt;li&gt;Drop materialized view&lt;/li&gt;   &lt;li&gt;Insert into materialized view table from temp table (no aggregation required)&lt;/li&gt;   &lt;li&gt;Recreate materialized view&lt;/li&gt; &lt;/ol&gt; However this would sacrifice many of the performance benefits of the single stage manual insert.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Summary&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If there is an alternative mechnism for avoiding the MERGE then I'd be very glad to hear it, but this method may stand on its own if the alternatives do not allow direct path operations on the MV table or the sorting of the table data.&lt;br /&gt;&lt;br /&gt;There are also some clear benefits to this mechanism when you consider the refresh of multiple materialized views, but they will wait until after thanksgiving (if I escape both the long term and immediate threats to my health of deep-frying a turkey tomorrow).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Last Minute Addendum&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It occured to me just after posting this that another benefit of using a manual refresh is that you can avoid the overhead of calculating the extra columns required by the fast refresh mechanism, in this case the COUNT(*). I'll do a test on the benefits of that also.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112913169286787027?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112913169286787027/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112913169286787027' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112913169286787027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112913169286787027'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/11/optimizing-materialized-views-part-iii.html' title='Optimizing Materialized Views Part III: Manual Refresh Mechanisms'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112913493742217456</id><published>2005-11-14T07:00:00.000-07:00</published><updated>2005-11-14T10:01:36.283-07:00</updated><title type='text'>Choosing Partitioning Keys: For ETL or Reporting?</title><content type='html'>This is one of the &lt;a href="http://oraclesponge.blogspot.com/2005/10/reporting-wait-events-for-data.html"&gt;recursive thought processes&lt;/a&gt; that has been spun off from considering ways of optimizing the fast refresh of multiple materialized views: I must now be at a recursive depth well into double figures because I cannot recall how I got here at all. Anyway ...&lt;br /&gt;&lt;br /&gt;I was just browsing the 10gR2 documentation, and noticed the following comments &lt;a href="http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14223/refresh.htm#i1006199"&gt;here&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;"&lt;span style="font-style: italic;"&gt;The partitioning scheme of the data warehouse is often crucial in determining the efficiency of refresh operations in the data warehouse load process. In fact, the load process is often the primary consideration in choosing the partitioning scheme of data warehouse tables and indexes.&lt;/span&gt; &lt;p&gt;&lt;span style="font-style: italic;"&gt;The partitioning scheme of the largest data warehouse tables (for example, the fact table in a star schema) should be based upon the loading paradigm of the data warehouse.&lt;/span&gt;"&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I have no argument with "&lt;span style="font-style: italic;"&gt;The partitioning scheme ... is often crucial in determining the efficiency of refresh operations ..."&lt;/span&gt;, nor with &lt;span style="font-style: italic;"&gt;"&lt;/span&gt;&lt;span style="font-style: italic;"&gt;... the load process is often the primary consideration in choosing the partitioning scheme ..."&lt;/span&gt;: the former statement is self-evidently true and I'm sure that the latter is also true. However I do have a problem with, &lt;span style="font-style: italic;"&gt;"&lt;/span&gt;&lt;span style="font-style: italic;"&gt;The partitioning scheme ... &lt;span style="font-weight: bold;"&gt;should&lt;/span&gt; be based upon the loading paradigm ...".&lt;/span&gt; This strikes me as being not a very well thought-out piece of advice that depends more on an appeal to historical precedent or coincidence than it does to a rational design process. And it neglects the critical point that the partitioning scheme is &lt;span style="font-style: italic;"&gt;always&lt;/span&gt; crucial in determining the efficiency of reporting operations.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I recently &lt;a href="http://oraclesponge.blogspot.com/2005/08/partition-not-quite-pruning.html"&gt;wrote something&lt;/a&gt; that touched on this subject in a roundabout way by mentioning that I was migrating a fact table from a partitioning scheme that aligned with the ETL process to a new scheme that aligns with the reporting requirements. Throughout the migration I keep thinking of events Quite Some Time Ago in which the administrators of an OLTP database objected to the addition of new indexes on a couple of columns. Their rationale for this was superficially sound: that it would have slowed down both the insert of new rows and the subsequent update of those columns. While they were not discounting the benefits of the indexes for select operations they were treating the pros and the cons as if they were on a level footing. In fact at the time that the row was inserted the pain was already half over - a few days after the rows were inserted the newly indexed column's value would change once and from there on there were &lt;span style="font-style: italic;"&gt;only benefits&lt;/span&gt; to be gained from the new index. Substantial benefits they were too: two-orders of magnitude improvement in the performance of some key reporting queries.&lt;br /&gt;&lt;/p&gt; &lt;p&gt;Now that isn't the be all and end all of the considerations. To be completely fair we should also consider the sensitivity of the system (or the business) to the effects of the changes at the time that they are experienced. Taking the example above, if the loading of new data or the subsequent change to the indexed value was a critical process on which there were particular time restrictions, while the select statements that benefited were part of a batch operation with no current performance problems (in terms of whether the business was impacted by it running for longer than it could have with the index in place) then the &lt;span style="font-style: italic;"&gt;technical&lt;/span&gt; benefits of the additional indexes might have been outweighed by &lt;span style="font-style: italic;"&gt;operational&lt;/span&gt; issues.&lt;br /&gt;&lt;/p&gt; &lt;p&gt;So to appreciate the impact of a design feature on a system you not only have to consider whether those features represent potential benefits and detriments, but you have to weight them by a couple of other factors:&lt;br /&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;How often the benefit or detriment occurs&lt;/li&gt;   &lt;li&gt;How sensitive the system's operations are to the benefits and detriments occuring when they do.&lt;/li&gt; &lt;/ol&gt;   &lt;p&gt;So back to the matter of the partitioning.&lt;br /&gt;&lt;/p&gt; &lt;p&gt;Hopefully the parallels between the situations are pretty clear. We have design choices (to index or not to index ... to partition according to the convenience of either the ETL procees or the reporting queries) that impose costs and benefits on different operational stages in the data handling.&lt;br /&gt;&lt;/p&gt; &lt;p&gt;Now let us look at the costs and benefits of taking different decisions in the partitioning, and we will start here by stating the obvious: &lt;span style="font-style: italic;"&gt;that there is only a difference between the two partitioning schemes when the ETL and the reporting processes use different logical bases for identifying record sets of interest&lt;/span&gt;. If your data arrives in sets that correspond to the reporting requirements then this is not an issue.&lt;br /&gt;&lt;/p&gt;  &lt;p&gt;I'll not rehash on the situation that caused the migration from an ETL-based partitioning scheme to a report-based partitioning scheme, but in brief the users are interested in reports based on the date of a financial transaction, but financial transactions often arrive very "late". For example, transactions for March 2005 could be transmitted in September 2005.&lt;br /&gt;&lt;/p&gt; &lt;p&gt;Let us suppose then that we follow the advice given in the documentation. We partition our fact table by some natural or "synthetic" date (synthetic in the sense that it does not represent a business object) that represents the arrival period of the data, say "DAY_OF_FILE_ARRIVAL". This is a great convenience to the ETL programmer, who can transform the new data set into a table having the same structure as the fact table (without partitioning, or partitioned if the fact table is composite partitioned), create or rebuild indexes on it, analyze it, handle new or changed dimensional values, then perform a partition exchange with the fact table to make the new data available to the user community.&lt;br /&gt;&lt;/p&gt; &lt;p&gt;However the users are then querying by "DATE_OF_TRANSACTION". For example they specify a range-based predicate of &lt;span style="font-family:courier new;"&gt;DATE_OF_TRANSACTION between '01-jan-2005' and '31-Jan-2005'&lt;/span&gt;. As this represents a small fraction of the data in the fact table, and as the rows are fairly well clustered, an index-based access method is used to retrieve the rows. In fact until the number of fact table blocks to be touched starts to exceed some threshold like 10% of the total, an index-based access method can be expected, with the undesirably high number of logical reads and small physical read size that you'd expect.&lt;br /&gt;&lt;/p&gt; &lt;p&gt;So in this scenario partition pruning for the reporting queries has been lost and with it has gone arguably the single most effective means of enhancing query performance against a large fact table, short of slapping materialized views all over it or using parallel query (which I take rather for granted in a data warehousing environment).&lt;br /&gt;&lt;/p&gt; &lt;p&gt;If we adopted the alternative partitioning scheme based on DATE_OF_TRANSACTION then partition pruning sanity would return to user reports, but at what cost to the ETL process?&lt;br /&gt;&lt;/p&gt; &lt;p&gt;First, let's consider what alternatives there might be to a simple partition exchange-based loading method. In practice there is just one -- the direct path insert, either serial or parallel. While a full quantitative comparison of the partition exchange and direct path inserts is not not going to be presented right here and now (although maybe I'll add it to my list), I &lt;span style="font-style: italic;"&gt;feel&lt;/span&gt; that direct path inserts are not actually such a bad method for fact table loading. I'd consider the major disadvantage to be that they generate more redo because you are modifying enabled indexes for which the nologging attribute is not respected. In terms of manageability the pros and cons are mixed. On the one hand, you no longer need to worry about identifying which partition the data has to be exchanged with (if you ever did worry about that).&lt;br /&gt;&lt;/p&gt; &lt;p&gt;As far as statistics are concerned you do need to either allow monitoring and DBMS_Stats to handle the identification and collection of modified table statistics, or you need to start worrying about partitions again and implementing your own mechnaism for refreshing partition-level statistics. I have a feeling that while the latter approach may be more trouble by several orders of magnitude, it might still be preferable to the monitoring option. As the documentation &lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10752/stats.htm#40822"&gt;here&lt;/a&gt; states, "&lt;span style="font-style: italic;"&gt;If a monitored table has been modified more than 10%, then these statistics are considered stale and gathered again.&lt;/span&gt;" While I am no fanatic about making sure that statistics are right up to date you would certainly want to think about whether this threshold is low enough, particularly in regard to histograms - it doesn't take a 10% change in the number of rows for a histogram to be significantly altered, particularly if business conditions and data distributions change with time.&lt;br /&gt;&lt;/p&gt; &lt;p&gt;I can't believe that I just set myself up for another blog topic. * sigh * Another recursive layer -- I need a vacation.&lt;br /&gt;&lt;/p&gt; &lt;p&gt;Another consideration is how well the batches of new records correlate with the partitioning scheme. Maybe your batch of new records is scattered all over a bunch of partitions, or maybe nearly all of the data is going to a single partition with a few rows scattered over a handful of others. In fact I prefer to think about this the other way around -- instead of thinking about this from the view point of how the new data is going to be split I'd rather consider what is ging to happen to the fact table partitions. Here are a few different scenarios:&lt;br /&gt;&lt;/p&gt; &lt;ol&gt;   &lt;/ol&gt; &lt;ul&gt;   &lt;li&gt;One empty partition to be populated, one other partition to gain around 1,000 rows (0.01% of current total)&lt;/li&gt;   &lt;li&gt;One empty partition to be populated, six others to gain between one and three million rows (1-3% of total), five others to gain between 10 and 1000 (0.001-0.1% of current total)&lt;/li&gt;   &lt;li&gt;All partitions to gain around one million rows (1% of total)&lt;/li&gt; &lt;/ul&gt; &lt;ol&gt;         &lt;/ol&gt;How you treat these different scenarios, and how confortable you are with them, depends on where the breakeven point lies for you in your tolerance of ETL complexity and performance, and probably therefore on your ETL tool also.&lt;br /&gt;&lt;br /&gt;When a partition starts out with data we have a couple of options.&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Copy the data into a new/empty table in nologging mode, insert the new data, rebuild indexes, then partition exchange with the original.&lt;/li&gt;   &lt;li&gt;Direct path load into the original partition, again with the option of disabling indexes where possible.&lt;/li&gt; &lt;/ol&gt; Which one of these approaches works best for you depends on a few factors. The former approach is certainly more challenging to program, while the latter will incur higher overhead on logging (although the overall i/o subsystem load may well be smaller).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So there you have it. I don't think that there is a clear cut case for partitioning according to ETL requirements, and the benefits of partitioning by reporting requirements are certainly enough to compel a close examination of the alternative to loading exclusively by partition exchange. Does this seem like an issue worthy of being rasied as a documentation bug? I'm not sure, but if people think it important then I'd be willing to raise one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112913493742217456?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112913493742217456/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112913493742217456' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112913493742217456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112913493742217456'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/11/choosing-partitioning-keys-for-etl-or.html' title='Choosing Partitioning Keys: For ETL or Reporting?'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113183378369211911</id><published>2005-11-12T15:13:00.000-07:00</published><updated>2005-11-12T15:16:23.730-07:00</updated><title type='text'>Oracle Patent on Load-Dependent Query Optimizer Costing</title><content type='html'>As if we don't have enough factors to consider when scratching our heads over execution plans, we'll soon have to consider server load as a variable if Oracle implements the technology described in Patent &lt;a href="http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO2&amp;Sect2=HITOFF&amp;amp;u=/netahtml/search-adv.htm&amp;r=10&amp;amp;p=1&amp;f=G&amp;amp;l=50&amp;d=ptxt&amp;amp;S1=%28%28Oracle.ASNM.+AND+International%29+AND+Corporation%29&amp;OS=an/Oracle+and+International+and+Corporation&amp;amp;RS=%28%28AN/Oracle+AND+International%29+AND+Corporation%29"&gt;6,957,211&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;When will the madness stop? "When", I ask you?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113183378369211911?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113183378369211911/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113183378369211911' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113183378369211911'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113183378369211911'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/11/oracle-patent-on-load-dependent-query.html' title='Oracle Patent on Load-Dependent Query Optimizer Costing'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113165262821559643</id><published>2005-11-10T12:56:00.000-07:00</published><updated>2005-11-10T12:57:08.266-07:00</updated><title type='text'>Choosing an Ordering Method for Best Table Compression</title><content type='html'>Some comments here: http://www.phpbbserver.com/phpbb/viewtopic.php?t=614&amp;amp;mforum=dizwellforum&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113165262821559643?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113165262821559643/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113165262821559643' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113165262821559643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113165262821559643'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/11/choosing-ordering-method-for-best.html' title='Choosing an Ordering Method for Best Table Compression'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113112689141494973</id><published>2005-11-04T10:53:00.000-07:00</published><updated>2005-11-04T10:54:51.463-07:00</updated><title type='text'>Oracle XE Registration</title><content type='html'>Has anyone successfully registered this yet? I've submitted my registration three times so far without getting an acknowledgement. E-Mail details are correct and everything.&lt;br /&gt;&lt;br /&gt;Anyone got any clues on this?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113112689141494973?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113112689141494973/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113112689141494973' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113112689141494973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113112689141494973'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/11/oracle-xe-registration.html' title='Oracle XE Registration'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-113043590751807328</id><published>2005-10-27T11:55:00.000-06:00</published><updated>2005-10-27T11:58:27.553-06:00</updated><title type='text'>Dynamic Sampling at AskTom</title><content type='html'>I saw an interesting question on dynamic sampling over at Ask Tom and ended up pretty much dumping a half-finished blog posting in reply. I'll save myself the elctrons of publishing it here by just linking to it. &lt;a href="http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:4105951726381#50320263213713"&gt;Enjoy&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-113043590751807328?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/113043590751807328/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=113043590751807328' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113043590751807328'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/113043590751807328'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/10/dynamic-sampling-at-asktom.html' title='Dynamic Sampling at AskTom'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112862236390915781</id><published>2005-10-06T07:00:00.000-06:00</published><updated>2005-10-06T17:39:17.783-06:00</updated><title type='text'>Testing the Trace Loader</title><content type='html'>As I said &lt;a href="http://oraclesponge.blogspot.com/2005/10/reporting-wait-events-for-data.html"&gt;yesterday&lt;/a&gt;, I've been fiddling around with loading trace files into the database for analysis, and today I was looki&lt;span style="font-family:georgia;"&gt;ng f&lt;/span&gt;or a good test case to see how the numbers are coming out. The obvious example to choose was the &lt;a href="http://oraclesponge.blogspot.com/2005/09/reducing-work-of-refreshing-multiple_15.html"&gt;direct path enhancement&lt;/a&gt; to materialized view refresh that I also wrote about recently.&lt;br /&gt;&lt;br /&gt;Here is my test script:&lt;br /&gt;&lt;pre&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;drop table master;&lt;br /&gt;drop table master_test_data;&lt;br /&gt;drop materialized view master_mv1;&lt;br /&gt;&lt;br /&gt;create table master&lt;br /&gt;   (&lt;br /&gt;   location_cd  number not null,&lt;br /&gt;   tx_timestamp date   not null,&lt;br /&gt;   product_cd   number not null,&lt;br /&gt;   tx_qty       number not null,&lt;br /&gt;   tx_cst       number not null&lt;br /&gt;   )&lt;br /&gt;pctfree 0&lt;br /&gt;nologging&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;create materialized view log on master&lt;br /&gt;with rowid&lt;br /&gt;   (&lt;br /&gt;   location_cd,&lt;br /&gt;   tx_timestamp,&lt;br /&gt;   product_cd,&lt;br /&gt;   tx_qty,&lt;br /&gt;   tx_cst&lt;br /&gt;   )&lt;br /&gt;including new values&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;create materialized view master_mv1&lt;br /&gt;Using No Index&lt;br /&gt;Refresh Fast On Commit&lt;br /&gt;Enable Query Rewrite&lt;br /&gt;As&lt;br /&gt;Select&lt;br /&gt;   location_cd,&lt;br /&gt;   trunc(tx_timestamp,'MM') tx_month,&lt;br /&gt;   sum(tx_qty) s_tx_qty,&lt;br /&gt;   sum(tx_cst) s_tx_cst,&lt;br /&gt;   count(*)    c_star&lt;br /&gt;from&lt;br /&gt;   master&lt;br /&gt;group by&lt;br /&gt;   location_cd,&lt;br /&gt;   trunc(tx_timestamp,'MM')&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;create materialized view master_mv2&lt;br /&gt;Using No Index&lt;br /&gt;Refresh Fast On Commit&lt;br /&gt;Enable Query Rewrite&lt;br /&gt;As&lt;br /&gt;Select&lt;br /&gt;   product_cd,&lt;br /&gt;   trunc(tx_timestamp,'MM') tx_month,&lt;br /&gt;   sum(tx_qty) sum_tx_qty,&lt;br /&gt;   sum(tx_cst) sum_tx_cst,&lt;br /&gt;   count(*)    c_star&lt;br /&gt;from&lt;br /&gt;   master&lt;br /&gt;group by&lt;br /&gt;   product_cd,&lt;br /&gt;   trunc(tx_timestamp,'MM')&lt;br /&gt;/&lt;br /&gt;&lt;br /&gt;create table master_test_data&lt;br /&gt;   (&lt;br /&gt;   location_cd  not null,&lt;br /&gt;   tx_timestamp not null,&lt;br /&gt;   product_cd   not null,&lt;br /&gt;   tx_qty       not null,&lt;br /&gt;   tx_cst       not null&lt;br /&gt;   )&lt;br /&gt;pctfree 0&lt;br /&gt;nologging&lt;br /&gt;as&lt;br /&gt;select&lt;br /&gt;   trunc(dbms_random.value(1,10)),&lt;br /&gt;   to_date('01-jan-2005','DD-Mon-YYYY')&lt;br /&gt;      + dbms_random.value(1,31),&lt;br /&gt;   trunc(dbms_random.value(1,1000)),&lt;br /&gt;   trunc(dbms_random.value(1,10)),&lt;br /&gt;   trunc(dbms_random.value(1,100),2)&lt;br /&gt;from&lt;br /&gt;   dual&lt;br /&gt;connect by&lt;br /&gt;   1=1 and&lt;br /&gt;   level &lt; 1000001&lt;br /&gt;/&lt;br /&gt;commit&lt;br /&gt;/&lt;br /&gt;select count(*) from master_test_data&lt;br /&gt;/&lt;br /&gt;alter session set timed_statistics = true;&lt;br /&gt;alter session set max_dump_file_size=1000000000;&lt;br /&gt;alter session set events '10046 trace name context forever, level 8';&lt;br /&gt;&lt;br /&gt;insert into master&lt;br /&gt;select *&lt;br /&gt;from   master_test_data&lt;br /&gt;where  rownum &lt; 100001&lt;br /&gt;/&lt;br /&gt;commit&lt;br /&gt;/&lt;br /&gt;exit&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Rather straightforward stuff. The "select count(*)" of rows in the master test data table is just to eliminate the possiblity of the test results getting skewed by &lt;a href="http://www.jlcomp.demon.co.uk/cleanout.html"&gt;delayed block cleanout&lt;/a&gt;, by the way. The example above is for the conventional path insert. The only change required for the direct path enhancement to kick-in is to use an APPEND hint in the last insert statement.&lt;br /&gt;&lt;br /&gt;So, having identified the trace files I issue the following command:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="font-family:courier new;"&gt;begin&lt;br /&gt; trace.purge; -- purges all data from the trace file repository&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;span style="font-family:courier new;"&gt;   trace.load_file&lt;br /&gt;   (directory   =&gt;'UDUMP',&lt;br /&gt;    file_name   =&gt; 'slimdb_ora_4412.trc',&lt;br /&gt;    identify_as =&gt; 'direct path',&lt;br /&gt;    debug       =&gt; 0,&lt;br /&gt;    log_extents =&gt; true,&lt;br /&gt;    log_files   =&gt; true);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;span style="font-family:courier new;"&gt;   trace.load_file&lt;br /&gt;   (directory   =&gt;'UDUMP',&lt;br /&gt;    file_name   =&gt; 'slimdb_ora_4600.trc',&lt;br /&gt;    identify_as =&gt; 'conv path',&lt;br /&gt;    debug       =&gt; 0,&lt;br /&gt;    log_extents =&gt; true,&lt;br /&gt;    log_files   =&gt; true);&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;This allows me to query the trace file information directly, giving me such output as:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="font-family:courier new;"&gt;SQL&gt; select&lt;br /&gt;2     substr(identify_as,1,12),&lt;br /&gt;3     op_name,&lt;br /&gt;4     sum(op_c),&lt;br /&gt;5     sum(op_e)/1000000 sec,&lt;br /&gt;6     count(*)&lt;br /&gt;7  from&lt;br /&gt;8  (&lt;br /&gt;9  select&lt;br /&gt;10     identify_as,&lt;br /&gt;11     cur_dep,&lt;br /&gt;12     f.file#,&lt;br /&gt;13     f.file_name,&lt;br /&gt;14     c.cursor#,&lt;br /&gt;15     o.op_name,&lt;br /&gt;16     OP_C  ,&lt;br /&gt;17     OP_E  ,&lt;br /&gt;18     OP_P  ,&lt;br /&gt;19     OP_CR ,&lt;br /&gt;20     OP_CU ,&lt;br /&gt;21     OP_TIM&lt;br /&gt;22  from&lt;br /&gt;23     trace_ops o,&lt;br /&gt;24     trace_cursors c,&lt;br /&gt;25     trace_files f&lt;br /&gt;26  where&lt;br /&gt;27     f.file#   = c.file# and&lt;br /&gt;28     c.cursor# = o.cursor#&lt;br /&gt;29     )&lt;br /&gt;30  group by&lt;br /&gt;31     substr(identify_as,1,12),&lt;br /&gt;32     op_name&lt;br /&gt;33  order by&lt;br /&gt;34     1,2,4 desc&lt;br /&gt;35  /&lt;br /&gt;&lt;br /&gt;SUBSTR(IDENT OP_NAME     SUM(OP_C)        SEC   COUNT(*)&lt;br /&gt;------------ ---------- ---------- ---------- ----------&lt;br /&gt;conv path    EXEC         20875000  33.358519     100342&lt;br /&gt;conv path    FETCH         2296875   3.026768        304&lt;br /&gt;conv path    PARSE          156250    .661319        333&lt;br /&gt;direct path  EXEC          2890625   3.476836        350&lt;br /&gt;direct path  FETCH          140625    .406403        402&lt;br /&gt;direct path  PARSE          859375   1.302354        224&lt;br /&gt;&lt;br /&gt;6 rows selected.&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;span style="font-family:georgia;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:georgia;"&gt;Of course all the interesting work is going on behind the scenes in the form of recursive SQL:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;SQL&gt; select&lt;br /&gt;2     substr(identify_as,1,12),&lt;br /&gt;3     cur_dep,&lt;br /&gt;4     op_name,&lt;br /&gt;5     sum(op_c),&lt;br /&gt;6     sum(op_e)/1000000 sec,&lt;br /&gt;7     count(*)&lt;br /&gt;8  from&lt;br /&gt;9  (&lt;br /&gt;10  select&lt;br /&gt;11     identify_as,&lt;br /&gt;12     cur_dep,&lt;br /&gt;13     f.file#,&lt;br /&gt;14     f.file_name,&lt;br /&gt;15     c.cursor#,&lt;br /&gt;16     o.op_name,&lt;br /&gt;17     OP_C  ,&lt;br /&gt;18     OP_E  ,&lt;br /&gt;19     OP_P  ,&lt;br /&gt;20     OP_CR ,&lt;br /&gt;21     OP_CU ,&lt;br /&gt;22     OP_TIM&lt;br /&gt;23  from&lt;br /&gt;24     trace_ops o,&lt;br /&gt;25     trace_cursors c,&lt;br /&gt;26     trace_files f&lt;br /&gt;27  where&lt;br /&gt;28     f.file#   = c.file# and&lt;br /&gt;29     c.cursor# = o.cursor#&lt;br /&gt;30     )&lt;br /&gt;31  group by&lt;br /&gt;32     substr(identify_as,1,12),&lt;br /&gt;33     cur_dep,&lt;br /&gt;34     op_name&lt;br /&gt;35  order by&lt;br /&gt;36     1,2,3,5 desc&lt;br /&gt;37  /&lt;br /&gt;&lt;br /&gt;SUBSTR(IDENT    CUR_DEP OP_NAME     SUM(OP_C)        SEC   COUNT(*)&lt;br /&gt;------------ ---------- ---------- ---------- ---------- ----------&lt;br /&gt;conv path             0 EXEC         14484375  22.637736         18&lt;br /&gt;conv path             0 FETCH         2125000   2.342986         15&lt;br /&gt;conv path             0 PARSE           93750     .56999         16&lt;br /&gt;conv path             1 EXEC          6343750  10.694057     100188&lt;br /&gt;conv path             1 FETCH          109375    .619292        147&lt;br /&gt;conv path             1 PARSE           62500    .079386        187&lt;br /&gt;conv path             2 EXEC            46875    .026135        128&lt;br /&gt;conv path             2 FETCH           62500    .062152        134&lt;br /&gt;conv path             2 PARSE               0    .009992        128&lt;br /&gt;conv path             3 EXEC                0     .00006          1&lt;br /&gt;conv path             3 FETCH               0    .002111          1&lt;br /&gt;conv path             3 PARSE               0    .001875          1&lt;br /&gt;conv path             4 EXEC                0    .000531          7&lt;br /&gt;conv path             4 FETCH               0    .000227          7&lt;br /&gt;conv path             4 PARSE               0    .000076          1&lt;br /&gt;direct path           0 EXEC          1718750   2.218695          3&lt;br /&gt;direct path           0 PARSE           31250     .17893          2&lt;br /&gt;direct path           1 EXEC           750000    .841392        138&lt;br /&gt;direct path           1 FETCH           15625    .128181         91&lt;br /&gt;direct path           1 PARSE          343750     .47748        133&lt;br /&gt;direct path           2 EXEC           140625     .14998        124&lt;br /&gt;direct path           2 FETCH          109375    .168264        124&lt;br /&gt;direct path           2 PARSE          421875     .52747         27&lt;br /&gt;direct path           3 EXEC           281250    .260751         78&lt;br /&gt;direct path           3 FETCH           15625    .068693        180&lt;br /&gt;direct path           3 PARSE           46875    .109109         61&lt;br /&gt;direct path           4 EXEC                0    .006018          7&lt;br /&gt;direct path           4 FETCH               0    .041265          7&lt;br /&gt;direct path           4 PARSE           15625    .009365          1&lt;br /&gt;&lt;br /&gt;29 rows selected.&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;&lt;/pre&gt;&lt;br /&gt;So what leaps out at us here (or it would do if Blogger didn't trim leading and multiple white spaces) is an enormous number of executions at a recursive depth (cur_dep) of 1 in the conventional path refresh -- coincidentally (well, actually not at all coincidentally) slightly more than the number of rows being inserted into the master table.&lt;br /&gt;&lt;br /&gt;This of course, is the maintenance of the materialized view log being performed in an inefficient row-by-row manner:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="font-family:courier new;"&gt;SQL&gt; select CUR_SQL_TEXT&lt;br /&gt;2  from   trace_cursors&lt;br /&gt;3  where  cursor# =&lt;br /&gt;4     (&lt;br /&gt;5     select cursor#&lt;br /&gt;6     from&lt;br /&gt;7     (&lt;br /&gt;8     Select cursor#,count(*)&lt;br /&gt;9     from   trace_ops&lt;br /&gt;10     where  op_name = 'EXEC'&lt;br /&gt;11     group by cursor#&lt;br /&gt;12     order by 2 desc&lt;br /&gt;13     )&lt;br /&gt;14     where rownum = 1&lt;br /&gt;15     )&lt;br /&gt;16  /&lt;br /&gt;&lt;br /&gt;CUR_SQL_TEXT&lt;br /&gt;--------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;INSERT /*+ IDX(0) */ INTO "DAVE"."MLOG$_MASTER" (dmltype$$,old_new$$,snaptime$$,&lt;br /&gt;&lt;br /&gt;change_vector$,m_row$,"LOCATION_CD","TX_TIMESTAMP","PRODUCT_CD","TX_QTY","TX_C&lt;br /&gt;&lt;br /&gt;ST") VALUES (:d,:o,to_date('4000-01-01:00:00:00','YYYY-MM-DD:HH24:MI:SS'),:c,:m,&lt;br /&gt;&lt;br /&gt;:1,:2,:3,:4,:5)&lt;br /&gt;&lt;span style="font-family:georgia;"&gt;&lt;br /&gt;Hey, at least it's using bind variables!&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112862236390915781?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112862236390915781/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112862236390915781' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112862236390915781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112862236390915781'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/10/testing-trace-loader.html' title='Testing the Trace Loader'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112852006656055900</id><published>2005-10-05T06:30:00.000-06:00</published><updated>2005-10-06T22:56:01.750-06:00</updated><title type='text'>Reporting Wait Events For Data Warehouse Queries</title><content type='html'>Funny how easy it is to get side-tracked. Well not really side-tracked, but just more and more involved in one particular thing, so that you end up burrowing so deeply into it that it loses all relevance to the real world. Just as a simple SQL statement generates deeper and deeper levels of more and more obscure recursive statements, so it can be with the most simple of tasks.&lt;br /&gt;&lt;br /&gt;Those of you still awake may recall that I was looking at materialized view refresh, and in the course of getting to grips with the optimum refresh methodology for fast refreshing multiple MV's I've been picking the bones out of some lovely warm trace files. My guidance has come from two books that are probably familiar to many readers, and which have become indispensible to me: &lt;a href="http://books.mcgraw-hill.com/getbook.php?isbn=007222729X&amp;template=oraclepress"&gt;&lt;span style="font-style: italic;"&gt;Oracle Wait Interface: A Practical Guide to Performance Diagnostics &amp; Tuning; Shee, Deshpande and Gopalakrishnan&lt;/span&gt;&lt;span style="font-style: italic;"&gt;; Oracle Press&lt;/span&gt;&lt;/a&gt;, and &lt;a href="http://www.oreilly.com/catalog/optoraclep/"&gt;&lt;span style="font-style: italic;"&gt;Optimizing Oracle Performance; Millsap and Holt&lt;/span&gt;&lt;span style="font-style: italic;"&gt;; O'Reilly&lt;/span&gt;&lt;/a&gt;. And let me first say that they are a beautiful compliment to each other. While the former goes into just the right level of detail on how to understand and mitigate the wait events themselves, the latter presents a methodology for data capture and event interpretation backed up with a strong background in &lt;a href="http://en.wikipedia.org/wiki/Queue_theory"&gt;queueing theory&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Now the usual challenge is to translate an approach aimed at OLTP databases into something that we can use in data warehousing, and fortunately this is not too tricky in the case of wait event capture and analysis. One of the major challenges associated with wait event analysis on OLTP databases is simply in capturing the correct data in the first place (a topic addressed in depth by the Millsap/Holt book) but this is relatively easy in "the other world": a problematic query that we are interested in tuning is generally well-known and easily isolated, whether it is part of the ETL routine or part of a report.&lt;br /&gt;&lt;br /&gt;Issues relating to use of shared servers, which can scatter a single session's wait events among multiple trace files practically at random, are also probably rare. Shared server configurations are inherently problematic in an environment where system load is dominated by fewer, longer running queries than an OLTP system would experience, and so are rarely used.&lt;br /&gt;&lt;br /&gt;On the other hand we do have the challenge of parallel query, in which the most meaningful wait events get pushed to different trace files, one for each PQ process. Without identifying these files, capturing their data, and consolidating them into a single entity for analysis there is little that can usefully be done.&lt;br /&gt;&lt;br /&gt;And now a word about recursive SQL. Recursive SQL statements are issued by Oracle in support of the execution of the SQL statements submitted to the database. They are used to parse the query, to maintain the data dictionary (for example to add extents to table and index segments), to perform dynamic sampling, to retrieve information on segments for the optimizer to use, etc.. So we might be able to deduce immediately that recursive SQL plays a very large role in the execution of data warehouse queries for a number of reasons, the foremost of which are the high parse ratio and the complexity of the objects that the optimizer has to consider.&lt;br /&gt;&lt;br /&gt;The high parse ratio is caused by our desire for the optimizer to be sensitive to literal values in the predicates (histogram usage being particularly important in this environment), and where an OLTP system could be unscalable due to the workload imposed by a high hard parse rate, the longer duration of the data warehouse queries renders this overhead &lt;span style="font-style: italic;"&gt;less&lt;/span&gt; significant. Not wholly insignificant, but not so significant that it is worth eliminating entirely.&lt;br /&gt;&lt;br /&gt;Now there is also the issue of object complexity. I venture to suggest that in data warehousing we have a much higher probability that partitioning is being used, and also that we will be leveraging partition pruning. So despite the apprant simplicity of many queries against star schemas there are actualy a disproportionate number of data and index segments for the optimizer to be aware of. There is also a high chance that we will be using query rewrite, and hence that there are a great many more objects to be considered even if they are never going to be touched by the optimized query.&lt;br /&gt;&lt;br /&gt;Now I rather glossed over the issue of how easy it is in a data warehouse to identify the SQL for which we want to the wait events. However if you read much of the literature on wait event analysis you will find that this is actually a very large part of the formal methodologies generally presented. Do you want to identify the queries with the longest duration, or the most logical reads, or the most physical I/O, or what other considerations are there? When data warehousing relieves us of that issue we are left with two other major issues:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;What makes our query run for so long?&lt;/li&gt;   &lt;li&gt;What can we do about it?&lt;/li&gt; &lt;/ul&gt; And these are by no means trivial tasks. However I would suggest that the first of these issues really ought to be more trivial than it currently is. Consider the steps we might follow in a wait event analysis for a hypothetical data warehouse query.&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Extract the query, along with representative predicate literals&lt;/li&gt;   &lt;li&gt;Execute the query with the 10046 event set at level 8 ("8" rhymes with "wait", which is how I remember that level 8 gives us wait events and level 4 gives us binds :) ... and level 12 gives us both of course).&lt;/li&gt;   &lt;li&gt;Find the trace files (parallel query giving us multiple files, of course)&lt;/li&gt;   &lt;li&gt;Run tkprof on the trace files to turn them into something readable&lt;/li&gt;   &lt;li&gt;Coalesce the results&lt;/li&gt;   &lt;li&gt;Analyze what events are causing us pain (generally I/O-related ones and sometimes high CPU usage, I find).&lt;/li&gt;   &lt;li&gt;For I/O related events examine what object they are occuring on, how many there are, their average duration, whether there are I/O hot spots on our devices etc..&lt;/li&gt; &lt;/ol&gt; For me the tricky part starts at step 4: I can extract queries, set events, find trace files without much problem, but the rest leaves me a little cold.&lt;br /&gt;&lt;br /&gt;Let's start with tkprof. A fine program in general, but remembering the options for sorting the queries is beyond me, and having listed my major wait events I then have to go probing through the raw file again plus querying the data dictionary to find out what segment and file the events occured on. And remember that we may have upwards of a dozen file to contend with. Unless I'm missing out on something, that means a dozen executions of tkprof then a manual process to merge and examine all those raw files anyway.&lt;br /&gt;&lt;br /&gt;Merging, sorting and reporting: these are the bread and butter tasks of a database, not a command-line programs. So while staring at the ceiling in the dark one night I had the following thoughts:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;"Load the raw files into the database then report on them from there."&lt;/li&gt;   &lt;li&gt;"That means I can link the I/O-related wait events directly to the data dictionary to get object and file names automatically".&lt;/li&gt;   &lt;li&gt;"That means we'd have a history of the the exact wait events and the real execution plan associated with a query within the database itself"&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;"That's so obvious that it must have been done before."&lt;/li&gt;   &lt;li&gt;"Even if it has, I bet I could do it easily and customize it for my own purposes."&lt;/li&gt; &lt;/ol&gt; So that's what I've been up to for the past couple of weeks, in the little time I have between my real work and my family, instead of going through the materialized view refresh analysis that I actually promised. But it's a step in the right direction anyway -- should make that process more easy.&lt;br /&gt;&lt;br /&gt;How do you go about desinging and implementing such a methodology then? Here are the aims that I started out with.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Load into database tables ther significant data from multiple trace files&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;For me the data of interest are the wait events, and in order to put them into a usable context I also need to associate them with SQL statements (cursors, in the trace file), the file name, operations such as PARSE, EXEC and FETCH. They all have to be stored in a set of dedicated tables.&lt;br /&gt;&lt;br /&gt;Exactly which data would we load for each of these types of trace information? As much as possible, and for the most part that means all of it. We can get timings, recursive depth (very useful!), user id's, just about anything we need.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Associate significant system data with the trace file data&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In our world of data warehousing we regularly add, truncate, split, merge and drop partitions, and when we do so we change the object id to which the wait event parameters refers. It seems prudent for this reason and for performance purposes (data dictionary views being notoriously cranky when it comes to joining to other data) to provide the option of storing the appropriate data at the time that the trace file is loaded.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Associate multiple trace files with a single report&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is of particular use in coalescing the results of multiple files generated by parallel query for a single submitted SQL statement. So we'd want to load multiple trace files and say "these belong together".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Provide predefined mechanisms for reporting on the events&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A set of views on the database tables was going to be required, to allow more simple custom queries to be defined on the trace data. Analagous to the data dictionary views provided in the database in fact. In just the same way as "select * from table(dbms_xplan.display())" reports on the most recently generated explain plan, we can provide a mechanism for reporting on the most recently loaded trace file(s) for example.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Provide some administrative tools for purging old data&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Purge all the data, or all the data prior to some date, and some options like that.&lt;br /&gt;&lt;br /&gt;The progress so far has been encouraging. Loading in a trace file with a known name is now a trivial task, and basic reporting on the events is a doddle. For example I'm currently using the following command to load a single file:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;begin&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   trace.load_file&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;     (directory   =&gt;'UDUMP',                -- 1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;      file_name   =&gt; 'slimdb_ora_4680.trc', -- 2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;      debug       =&gt; 0,                     -- 3&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;      log_extents =&gt; true,                 -- 4&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;      log_files   =&gt; true);                 -- 5&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;end;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;/&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The parameters are pretty intuitive:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;The name of the directory object that points to the location of the file to be loaded.&lt;/li&gt;   &lt;li&gt;The name of the file to be loaded (duh).&lt;/li&gt;   &lt;li&gt;The level of debugging message required (spat out through DBMS_OUTPUT).&lt;/li&gt;   &lt;li&gt;Whether to take a snapshot of the relevant entities in the dba_extents system view, to enhance later reporting (default "false" due to relatively high overhead).&lt;/li&gt;   &lt;li&gt;Whether to take a snapshot of the relevant entities in the dba_data files system view, to enhance later reporting (default "true").&lt;/li&gt; &lt;/ol&gt; With the data loaded I can then report in the following manner:&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;SQL&gt; select * from all_trace_files;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;     FILE# FILE_NAME                      READ_DATE&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;---------- ------------------------------ ---------&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    132440 slimdb_ora_4680.trc            05-OCT-05&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;SQL&gt; column SUM_WT_ELA format 999,999,990&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;SQL&gt; column AVG_WT_ELA format 999,999,990&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;SQL&gt; column waits format 999,990&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;SQL&gt; break on report&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;SQL&gt; compute sum of SUM_WT_ELA on report&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;SQL&gt; select substr(WT_NAME,1,25) wt_name,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  2  sum(WT_ELA) sum_wt_ela,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  3  avg(wt_ela) avg_wt_ela,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  4  count(*) waits&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  5  from last_trace_waits&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  6  group by substr(WT_NAME,1,25)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  7  /&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;WT_NAME                     SUM_WT_ELA   AVG_WT_ELA    WAITS&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;------------------------- ------------ ------------ --------&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;SQL*Net message from clie   27,372,317    9,124,106        3&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;SQL*Net message to client           14            5        3&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file scattered read       4,771,858       18,640      256&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read      1,490,384        3,644      409&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;                          ------------&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;sum                         33,634,573&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;SQL&gt; select   CUR_DEP,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  2           count(*)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  3  from     last_trace_cursors&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  4  group by cur_dep&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  5  order by 1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  6  /&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   CUR_DEP   COUNT(*)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;---------- ----------&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         0          2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         1        391&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         2       2189&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         3         92&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         4          2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         5          1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;6 rows selected.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;SQL&gt; set pagesize 100&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;SQL&gt; select substr(WT_NAME,1,23) wt_name,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  2  substr(segment_name,1,20) segment_name,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  3  sum(WT_ELA) sum_wt_ela,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  4  avg(wt_ela) avg_wt_ela,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  5  count(*) waits&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  6  from last_trace_obj_waits&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  7  group by substr(WT_NAME,1,23),substr(segment_name,1,20)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  8  order by 3 desc&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  9  /&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;WT_NAME                 SEGMENT_NAME           SUM_WT_ELA   AVG_WT_ELA    WAITS&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;----------------------- -------------------- ------------ ------------ --------&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file scattered read   FCT_FSA_1               4,698,204       19,908      236&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read INDSUBPART$             3,963,720        1,149    3,450&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read C_OBJ#_INTCOL#          2,355,677        4,403      535&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read C_FILE#_BLOCK#          2,129,218        1,342    1,587&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_OBJ2                    676,269        1,375      492&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_FILE#_BLOCK#            470,275        4,237      111&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read FCT_FSA_1                 417,323        5,962       70&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read TABSUBPART$               170,888        4,069       42&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file scattered read  INDCOMPART$               130,647        6,221       21&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read HIST_HEAD$                 62,906        7,863        8&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_INDSUBPART$              61,507        1,922       32&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file scattered read  TABCOMPART$                57,753        6,417        9&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_CDEF2                    34,272        4,284        8&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read SNAP$                      30,162        7,541        4&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read PARTOBJ$                   29,690        7,423        4&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read SUMAGG$                    24,404        6,101        4&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read INDCOMPART$                19,534        9,767        2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read SUMKEY$                    19,116        4,779        4&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read DIMJOINKEY$                17,296        4,324        4&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read PARTCOL$                   15,068        3,767        4&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read TABCOMPART$                14,988        7,494        2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read SUMDELTA$                  12,143       12,143        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_TABSUBPART$              11,146        5,573        2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_CDEF3                    10,627       10,627        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_SUBCOLTYPE1              10,131       10,131        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_NTAB2                     9,696        9,696        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_CCOL1                     9,366        4,683        2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read C_COBJ#                     9,322        9,322        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read SUM$                        8,722        4,361        2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_OBJ#_INTCOL#              7,496        7,496        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_SUBPARTCOL$               7,059        7,059        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_DIMATTR$_2                6,601        6,601        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read DEPENDENCY$                 6,432        3,216        2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_HH_OBJ#_INTCOL#           6,267        6,267        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_DEFSUBPART$               5,595        5,595        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read VIEW$                       5,231        5,231        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read DEFSUBPART$                 4,795        4,795        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_DEPENDENCY1               4,649        4,649        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_REFCON2                   3,544        3,544        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_PARTCOL$                  2,705        2,705        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file scattered read  SUM$                          742          371        2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_OPQTYPE1                    195          195        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read SUBPARTCOL$                   138          138        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;db file sequential read I_DIMLEVELKEY$_2              136          136        1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;                                             ------------&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;sum                                            15,541,655&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;The last two are pretty interesting, for a trace file based on a single star schema query, huh? Sorry about the crappy formating though.&lt;br /&gt;&lt;br /&gt;There's still work to do, and at the top of my list are the following:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;Allow grouping of trace files as a single logical entity&lt;/li&gt;   &lt;li&gt;Add more reporting views, focusing on filtering out recursive statements and on a set of "MY_%" views&lt;/li&gt;   &lt;li&gt;Associating recursive queries with their parents to enable reporting views based on CONNECT BY queries&lt;/li&gt;   &lt;li&gt;Better handling of files&lt;/li&gt;   &lt;li&gt;Creating a load script for the TRACELDR schema under which all this runs&lt;/li&gt;   &lt;li&gt;Creating a Trace Loader role to allow other users to access the package and views.&lt;/li&gt; &lt;/ul&gt; Based on that you can probably expect to hear from me again around Christmas.&lt;br /&gt;&lt;br /&gt;Nah, not really. Soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112852006656055900?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112852006656055900/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112852006656055900' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112852006656055900'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112852006656055900'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/10/reporting-wait-events-for-data.html' title='Reporting Wait Events For Data Warehouse Queries'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112681834048262562</id><published>2005-09-15T15:04:00.000-06:00</published><updated>2005-09-15T15:05:40.496-06:00</updated><title type='text'>Vacation Time</title><content type='html'>But it's just Dayton, OH, to cheer on the wife's running of the Air Force (half) marathon.&lt;br /&gt;&lt;br /&gt;See you next week.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112681834048262562?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112681834048262562/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112681834048262562' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112681834048262562'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112681834048262562'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/09/vacation-time.html' title='Vacation Time'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112672908311375360</id><published>2005-09-15T11:00:00.000-06:00</published><updated>2005-12-09T13:19:03.093-07:00</updated><title type='text'>Optimizing Materialized Views Part II: The Direct Path Insert Enhancement</title><content type='html'>&lt;span style="font-weight: bold; font-style: italic;"&gt;&lt;/span&gt;This follows on from some &lt;a href="http://oraclesponge.blogspot.com/2005/09/reducing-work-of-refreshing-multiple.html"&gt;recent thoughts&lt;/a&gt; about the need to find ways of optimizing fast refresh against multiple materialized views.&lt;br /&gt;&lt;br /&gt;In the documentation for both 9i and 10g you will find references to the optimization of fast refresh materialized views when direct-path insert is applied to the master table. For example &lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10736/refresh.htm#sthref806"&gt;here&lt;/a&gt; it states that "&lt;span style="font-style: italic;"&gt;Fast refresh can perform significant optimizations if it finds that only direct loads have occurred...&lt;/span&gt;". As far as I can tell the documentation gives no further information, but a couple of tests on the internal refresh mechanism are very revealing.&lt;br /&gt;&lt;br /&gt;Here is how conventional, non-Partition Change Tracking fast refresh works with conventional insert (two uses for the word "conventional" -- that won't be confusing at all):&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Bulk conventional insert into master_table (&lt;span style="font-style: italic;"&gt;Insert Into master_table ... select ...&lt;/span&gt; or other methods such as SQL*Loader conventional path)&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;Recursive SQL maintains MV log through multiple &lt;span style="font-style: italic;"&gt;Insert Into MLOG$... VALUES ()&lt;/span&gt;&lt;/li&gt;   &lt;li&gt;Commit&lt;/li&gt;   &lt;li&gt;MV maintained by &lt;span style="font-style: italic;"&gt;Merge Into MV Using (Select ... From MLOG$...)...&lt;/span&gt;&lt;/li&gt; &lt;/ol&gt; Here is the direct path enhancement:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Direct-path insert into master_table (&lt;span style="font-style: italic;"&gt;Insert /*+ APPEND */ Into master_table ... select ...&lt;/span&gt; or other methods such as SQL*Loader direct path)&lt;/li&gt;   &lt;li&gt;Commit&lt;/li&gt;   &lt;li&gt; MV maintained by &lt;span style="font-style: italic;"&gt;Merge Into MV Using (Select ... From ALL_SUMDELTA, Master_Table...)...&lt;/span&gt;&lt;/li&gt; &lt;/ol&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;br /&gt;The Difference&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here are the highlights of the differences:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;Although some recursive SQL is performed on an empty MLOG, there is no insert activity into the MLOG table at all.&lt;/li&gt;   &lt;li&gt;The MV's are not updated from the MLOG. Instead, the &lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10755/statviews_1176.htm#sthref1442"&gt;ALL_SUMDELTA&lt;/a&gt; view identifies the ranges of rowid's in the master_table that were just inserted, and a join between ALL_SUMDELTA and master_table is all that is needed to supply the change vectors required for the MV fast refresh. Recall that direct path insert creates contiguous blocks of records above the table's high water mark, and thus the new records are not interspersed with old records.&lt;br /&gt;&lt;/li&gt; &lt;/ul&gt; The loss of MLOG activity is probably the major reason for the performance boost (I'll pick the bones out of the trace file hopefully to confirm this next time). The multiple &lt;span style="font-style: italic;"&gt;Insert Into ... Values ...&lt;/span&gt; statements are an enormous overhead (measurable with SQL tracing), and they both prevent the insert into the MLOG from being a nologging operation and they also lose the benefits of a single bulk operation over multiple single operations. The lack of rows in the table for subsequent recursive SQL against MLOG also makes those SQL's an insignificant use of resources.&lt;br /&gt;&lt;br /&gt;The identification of the change vectors for the refresh process may also show improvement. In particular, where the MLOG represents a substantial proportion of the master table's columns &lt;span style="font-style: italic;"&gt;and&lt;/span&gt; the master table is compressed (not uncommon in fact tables) then the size of the change vectors stored in the MLOG is likely to exceed that of the new records in the table. On the other hand, the MLOG blocks are possibly still in the buffer cache at the time that the MV refresh takes place, which would not be the case with the new rows in the master table (which bypass the buffer cache).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Further Thoughts&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One inference that I'm drawing from all this is that the advantages of Partition Change Tracking fast refresh over conventional fast refresh are eroded enormously, which is a relief because I'm not a PCTFR fan at all for reasons that I think I've mentioned here before. If not, let me know.&lt;br /&gt;&lt;br /&gt;And here's another thought: if your intention is that MV refresh must never be based on conventional path insert because of the enormous performance loss, then could you place a trigger on the MLOG table to raise an error before insert?&lt;br /&gt;&lt;br /&gt;There's a little more work needed there to iron out the exact costs and benefits on the MV refresh process, but the performance increase on the lack of MLOG maintenance alone is an enormous boost.&lt;br /&gt;&lt;br /&gt;So to summarize:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;"&lt;span style="font-style: italic;"&gt;The best way to improve the performance of a task is not to do it at all&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;"&lt;span style="font-style: italic;"&gt;Bulk operations beat single-row operations&lt;/span&gt;"&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;Some Results&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now then, I don't want to suggest that the following results are formal and repeatable, but on my own test hardware I see the conventional method coming in at 17 minutes for the insert and 12 minutes for a refresh, in contrast to the direct method's 1 &lt;span style="font-style: italic;"&gt;second&lt;/span&gt; for the insert and 4 &lt;span style="font-style: italic;"&gt;seconds&lt;/span&gt; for the refresh. These number appear to be an improvement of such magnitude that I'm almost loath to publish them, so let's place a big "YOUR RESULTS MAY VARY" label on them for now.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;Next Time&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Anyway, that's all for now. I'm going to have a dig through the trace files for more detailed information.&lt;br /&gt;&lt;br /&gt;Oh by the way, this extremely powerful optimization is &lt;a href="http://www.linkgrinder.com/Patents/operations_aggregates_aggregates_multiple.html"&gt;patented&lt;/a&gt; by the Oracle Corporation, so hands off it ;)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;The Test Script&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;drop table master;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;drop table master_test_data;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;drop materialized view master_mv1;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;drop materialized view master_mv2;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;create table master&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   (&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   location_cd  number not null,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   tx_timestamp date   not null,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   product_cd   number not null,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   tx_qty       number not null,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   tx_cst       number not null&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   )&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;pctfree 0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;nologging&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;create materialized view log on master&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;with rowid&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   (&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   location_cd,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   tx_timestamp,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   product_cd,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   tx_qty,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   tx_cst&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   )&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;including new values&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;create materialized view master_mv1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Using No Index&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Refresh Fast On Commit&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Enable Query Rewrite&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;As&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Select&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   location_cd,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   trunc(tx_timestamp,'MM') tx_month,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   sum(tx_qty) s_tx_qty,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   sum(tx_cst) s_tx_cst,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   count(*)    c_star&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;from&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   master&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;group by&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   location_cd,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   trunc(tx_timestamp,'MM')&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;create materialized view master_mv2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Using No Index&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Refresh Fast On Commit&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Enable Query Rewrite&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;As&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Select&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   product_cd,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   trunc(tx_timestamp,'MM') tx_month,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   sum(tx_qty) sum_tx_qty,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   sum(tx_cst) sum_tx_cst,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   count(*)    c_star&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;from&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   master&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;group by&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   product_cd,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   trunc(tx_timestamp,'MM')&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;create table master_test_data&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   (&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   location_cd  not null,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   tx_timestamp not null,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   product_cd   not null,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   tx_qty       not null,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   tx_cst       not null&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   )&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;pctfree 0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;nologging&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;as&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;select&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   trunc(dbms_random.value(1,10)),&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   to_date('01-jan-2005','DD-Mon-YYYY')&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;      + dbms_random.value(1,31),&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   trunc(dbms_random.value(1,1000)),&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   trunc(dbms_random.value(1,10)),&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   trunc(dbms_random.value(1,100),2)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;from&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   dual&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;connect by&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   1=1 and&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   level &lt;= 100000 / &lt;/span&gt;&lt;span style="font-family:courier new;"&gt;commit&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;select count(*) from master_test_data&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;alter session set events '10046 trace name context forever, level 8'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;set timing on&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;insert /*+ append */  into master select * from master_test_data&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;where rownum &lt;= 50000 / &lt;/span&gt;&lt;span style="font-family:courier new;"&gt;commit&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;insert /*+ append */ into master select * from master_test_data&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;commit&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;exit&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112672908311375360?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112672908311375360/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112672908311375360' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112672908311375360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112672908311375360'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/09/optimizing-materialized-views-part-ii.html' title='Optimizing Materialized Views Part II: The Direct Path Insert Enhancement'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112670491658687059</id><published>2005-09-14T07:30:00.000-06:00</published><updated>2005-09-14T07:35:16.626-06:00</updated><title type='text'>From the "I'm no expert, but..." file</title><content type='html'>* Ahem *&lt;br /&gt;&lt;br /&gt;It would take a blind man, or one with work/hobbies to get on with instead, to avoid noticing all the talk about legal liability that folks might incur as the "owner"/"publisher" of a blog or forum. Serious stuff really, when some people say that just by allowing comments on your blog you are potentialy opening yourself up to potential liability for actionable defamation and such things.&lt;br /&gt;&lt;br /&gt;My policy has been to allow comments by anyone and so far the only one's I've removed have been spam. I must have a well-behaved readership, or something. :D&lt;br /&gt;&lt;br /&gt;Anyhoo, here's a resource that gives some pretty good news on the subject: the &lt;a href="http://www.eff.org/"&gt;Electronic Frontier Foundation&lt;/a&gt;'s &lt;a href="http://www.eff.org/bloggers/lg/"&gt;Legal Guide For Bloggers&lt;/a&gt;. The best news is that even if you don't have a blog then it's an interesting read all the same. For example, you can learn why a person included on a list of "&lt;a href="http://www.casp.net/felice.html"&gt;Top Ten Dumbasses&lt;/a&gt;" lost their case for libel. More seriously the page on &lt;a href="http://www.eff.org/bloggers/lg/faq-230.php"&gt;Section 230&lt;/a&gt; is an essential read.&lt;br /&gt;&lt;br /&gt;Like I say though, I'm no expert. But these people certainly seem to know what they're talking about.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112670491658687059?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112670491658687059/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112670491658687059' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112670491658687059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112670491658687059'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/09/from-im-no-expert-but-file.html' title='From the &quot;I&apos;m no expert, but...&quot; file'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112615976639738295</id><published>2005-09-08T00:05:00.000-06:00</published><updated>2005-09-08T00:09:26.396-06:00</updated><title type='text'>Webpage Guru</title><content type='html'>I don't want to speak too soon but I seem to have managed to alter the blog template to make the text area wider, through a technical process of mucking about with likely looking parameters (in many ways similar to network administration). Best of all nothing seems to be broken.&lt;br /&gt;&lt;br /&gt;If you have problems viewing this then let me know and I'll re-tweak it.&lt;br /&gt;&lt;br /&gt;Next challenge -- alter the background colour to an eye-watering bath sponge yellow.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112615976639738295?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112615976639738295/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112615976639738295' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112615976639738295'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112615976639738295'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/09/webpage-guru.html' title='Webpage Guru'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112602648993311092</id><published>2005-09-07T20:00:00.000-06:00</published><updated>2005-12-09T13:18:23.096-07:00</updated><title type='text'>Optimizing Materialized Views Part I: Principles For Analysis</title><content type='html'>&lt;span style="font-weight: bold; font-style: italic;"&gt;Some Background&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For a variety of reasons that are too painful to relate, query rewrite against some largish fact tables has been unsuccessful in the past, and manual builds of summary tables have been combined with the aggregate awareness of Business Objects to produce the same effect.&lt;br /&gt;&lt;br /&gt;The major drawback to this was the extraordinary number of hoops that had to be jumped through to make a change. The creation of a new summary table required coordinated efforts by a database designer, a DBA, a Business Objects designer and an ETL designer. As we all know the difficulty of coordinating such effort is related to something like the 7th power* of the number of people involved, so in other words by the time you have four people involved the job will take forever to get done.&lt;br /&gt;&lt;br /&gt;In other other-words, new summary tables were never added.&lt;br /&gt;&lt;br /&gt;However now that we have an apparantly robust and automatic method for maintaining the integrity of the materialized view refresh process and the resultant query rewrite ability, we find ourselves with a different choke-point on the creation of new materialized view-based summaries: the duration of the daily fast refresh process that accompanies the arrival of new fact table data. So here is a thought experiment that I'm going through at the moment.&lt;br /&gt;&lt;br /&gt;"&lt;span style="font-style: italic;"&gt;What techniques do we have for optimizing the refresh of materialized views?&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;For my own selfish reasons I'm thinking about conventional fast refresh of materialized views based on a single table. Any resemblance between this scenario and others is purely coincidental, but may exist all the same.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;The Scenario&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So let us examine a scenario where we have multiple fast-refreshable materialized views based on a single table. Personally when thinking about fast-refreshable MV's I prefer to consider that they are based on a &lt;a href="http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96524/c11schem.htm#18242"&gt;materialized view log&lt;/a&gt;, not the table itself. It is fairly trivial to demonstrate that a fast refresh of a materialized view is based entirely on the MV log without the requirement of access to the master table -- I did it for Oracle Support once by creating a fast refresh-on demand MV, and taking the tablespace with the master table offline before successfully refreshing the MV.&lt;br /&gt;&lt;br /&gt;The MV log table serves as a change-capture mechanism for its master table Some of them represent conventional summaries of the fact table. Some of them represent lists of distinct values of particular attribute columns in the table (such as Date_Of_Day, for example) in order to support fast retrieval of such values for the user interface. Some of these materialized views could logically be based on others, for example a list of Date_Of_Day values could be based on a summary table that stored metrics at a dimensionality of (Date_Of_Day, Location_Cd, Product_Cd).&lt;br /&gt;&lt;br /&gt;I suppose that we had also best define what we mean by "minimizing work". Again for my own selfish reasons I'm talking here about minimizing disk reads and writes, and in making those that occur as efficient as possible.&lt;br /&gt;&lt;br /&gt;The issue here is in the multiple scans of a materialized view log that are required in order to support the maintenance of materialized views. If you have seven materialized views based directly on a fact table then I don't see that Oracle can avoid seven consecutive scans of the log in order to maintain them.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Reducing The Workoad&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In approaching this problem I'm dividing the approaches up into a number of categories.&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;More efficient modifications to the materialized view log.&lt;/li&gt;   &lt;li&gt;More efficient reads of the materialized view log.&lt;/li&gt;   &lt;li&gt;Fewer reads of the materialized view log.&lt;/li&gt;   &lt;li&gt;More efficient update of the materialized views.&lt;/li&gt;   &lt;li&gt;Fewer materialized views.&lt;/li&gt;&lt;li&gt;Erm ...&lt;/li&gt;   &lt;li&gt;That's it.&lt;br /&gt;&lt;/li&gt;  &lt;/ol&gt; Now it seems to me that any one of these categories with the possible exception of the last two holds promise for more efficient MV maintenance -- when they are combined together we ought to be able to do something worthwhile.&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;&lt;br /&gt;Methodology&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I think that I can say without any fear of contradiction that if you want to make a process more efficient then you have to start by fully understanding it, and to my knowledge there are few tools more powerful for rummaging in the internals of an obscure Oracle process than a SQL trace.&lt;br /&gt;&lt;br /&gt;So here's the plan.&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Set up a representative scenario involving conventional fast refresh of multiple materialized views against a single master table, in the form of a SQL script.&lt;/li&gt;   &lt;li&gt;Execute the script with SQL tracing turned on.&lt;/li&gt;   &lt;li&gt;Extract from the trace file any statement that touches the materialized view log or the materialized views.&lt;/li&gt;   &lt;li&gt;Look for methodologies for optimizing each statement.&lt;/li&gt;   &lt;li&gt;Look for opportunities for reducing the number of statements executed.&lt;/li&gt;   &lt;li&gt;Measure.&lt;/li&gt;   &lt;li&gt;Change.&lt;/li&gt;   &lt;li&gt;Re-execute&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;Re-measure.&lt;/li&gt;   &lt;li&gt;Compare benefits&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;Et cetera&lt;/li&gt; &lt;/ol&gt; Well, as I mentioned previously these blogs have a habit of growing out-of-control, and personally I have the attention span of a goldfish so I'm going to split this up into a number of blogs. Hopefully this will also give anyone who spots an error or bad assumption the chance to leap in before I plow on down the Path of Wrongness.&lt;br /&gt;&lt;br /&gt;So in the next blog I'll set up the representative scenario, run a SQL trace on it, and carve out the most tender parts of the internals for our later consumption.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;continued &lt;a href="http://oraclesponge.blogspot.com/2005/09/reducing-work-of-refreshing-multiple_15.html"&gt;here&lt;/a&gt; ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;* This rule is based on a mixed bag of Democrat, Republican, and Anarcho-syndicalist technicians with varying number of children, wives, previous work commitments and deadlines. Your mileage may vary.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112602648993311092?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112602648993311092/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112602648993311092' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112602648993311092'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112602648993311092'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/09/optimizing-materialized-views-part-i.html' title='Optimizing Materialized Views Part I: Principles For Analysis'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112604282050547046</id><published>2005-09-06T15:37:00.000-06:00</published><updated>2005-09-06T15:40:20.523-06:00</updated><title type='text'>An Apology (no, not from me)</title><content type='html'>Just dabbling over at the website of &lt;a href="http://www.tricareonline.com/"&gt;TriCare&lt;/a&gt;, and came across what I thought was an extraordinary statement.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;b&gt;&lt;span style="font-style: italic;"&gt;  The registration functionality will continue to be available until further notice.  We will provide an update as soon as a new date is established for disabling the registration functionality. We apologize for any inconvenience this may cause.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;Um ... they appear to be apologising for their continued inability to prevent online registration. Shurely shome mishtake?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112604282050547046?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112604282050547046/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112604282050547046' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112604282050547046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112604282050547046'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/09/apology-no-not-from-me.html' title='An Apology (no, not from me)'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112603990629167004</id><published>2005-09-06T14:34:00.000-06:00</published><updated>2005-09-06T14:51:46.346-06:00</updated><title type='text'>What I'm Thinking About At The Moment</title><content type='html'>... is how to improve the performance of multiple materialized view fast refreshes based on a single master table.&lt;br /&gt;&lt;br /&gt;Hmmm.&lt;br /&gt;&lt;br /&gt;One of the values of this blogging thing is that you start with a problem, and then develop a plan to tackle it a certain way, and then you snap your fingers and think, "Best blog this right away!". Then as you write your thoughts down you realise, "What if someone suggests .... or what if they ask ... best write something about that option as well then!"&lt;br /&gt;&lt;br /&gt;Hence a brief note about your plan of action could turn into a near-total examination of the subject, some of which is not relevant to your situation anyway. In some cases you never see an end in sight -- in order to do justice to the topic (even one as narrowly focused as my current concern) in any rigorous sense you can see a twenty thousand word task ahead of you complete with scripts to justify every assumption and display every facet of the argument. This turns out to be so overwhelming that the blog collapses half-built under the pressure of &lt;span style="font-style: italic;"&gt;actually having to do something&lt;/span&gt; in a hurry.&lt;br /&gt;&lt;br /&gt;It's a hard life, eh? Well, I'm picking the bones out of my materialized view refresh issue before is gets turned into a problem, so hopefully I'll get to do justice to the topic.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112603990629167004?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112603990629167004/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112603990629167004' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112603990629167004'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112603990629167004'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/09/what-im-thinking-about-at-moment.html' title='What I&apos;m Thinking About At The Moment'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112560530307556361</id><published>2005-09-01T14:07:00.000-06:00</published><updated>2005-09-01T14:08:23.096-06:00</updated><title type='text'>Trivia for the day: the History Of The Ampersand</title><content type='html'>http://www.artlebedev.com/mandership/112/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112560530307556361?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112560530307556361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112560530307556361' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112560530307556361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112560530307556361'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/09/trivia-for-day-history-of-ampersand.html' title='Trivia for the day: the History Of The Ampersand'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112542148876338165</id><published>2005-08-31T06:30:00.000-06:00</published><updated>2005-08-31T06:44:45.770-06:00</updated><title type='text'>Partitions With And Without Rows</title><content type='html'>Just a quick note on a SQL technique I stumbled on that I thought I'd share.&lt;br /&gt;&lt;br /&gt;Having a partitioned fact table, with some partitions populated and others not, I have a series of materialized views that have not necessarily been entirely maintained. In this situation the materialized views are all partitioned with exactly the same scheme as the fact table but some of the partitions that have rows in the fact table do not have rows in the materialized views.&lt;br /&gt;&lt;br /&gt;I needed a query to rapidly identify those cases so that the offending MV partitions could be maintained, and I came up with a requirement as follows: &lt;span style="font-style: italic;"&gt;Identify all the partitions of the fact table that have at least one row, and for which there are no rows in the equivalent partition of a particular materialized view&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Because I had a usable naming convention for my partitions I was able to translate a partition name into a predicate very easily. for example given a partition name "Y2005M01" I can translate this into '01-jan-2005' using the simple method to_date(partition_name,'"Y"YYYY"M"MM'). You can try this yourself with:&lt;br /&gt;select to_char(sysdate,'"Y"YYYY"M"MM') from dual;&lt;br /&gt;...and then ...&lt;br /&gt;select to_date(to_char(sysdate,'"Y"YYYY"M"MM'),'"Y"YYYY"M"MM') from dual;&lt;br /&gt;&lt;br /&gt;So this allowed a query of the form:&lt;br /&gt;&lt;p style="margin-bottom: 0in;"&gt;&lt;span style="font-family:Courier,monospace;"&gt;Select partition_name&lt;br /&gt;From     user_tab_partitions utp&lt;br /&gt;Where   table_name = 'MY_FCT_TABLE' And&lt;br /&gt;             Exists&lt;br /&gt;         (Select /*+ norewrite */ 1&lt;br /&gt;          From MY_FCT_TABLE&lt;br /&gt;          Where date_of_month =&lt;br /&gt;                    to_date(utp.partition_name,&lt;br /&gt;                            '"Y"YYYY"M"MM')) And&lt;br /&gt;       Not Exists&lt;br /&gt;         (Select /*+ norewrite */ 1&lt;br /&gt;          From MY_FCT_TABLE_MV&lt;br /&gt;          Where date_of_month =&lt;br /&gt;                    to_date(utp.partition_name,&lt;br /&gt;                            '"Y"YYYY"M"MM'));&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;For a table having 175 partitions this identified the half-dozen or so problem partitions in around 3 seconds. Not too shabby, I thought.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112542148876338165?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112542148876338165/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112542148876338165' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112542148876338165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112542148876338165'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/partitions-with-and-without-rows.html' title='Partitions With And Without Rows'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112541770379765773</id><published>2005-08-30T09:57:00.000-06:00</published><updated>2005-09-06T11:26:24.206-06:00</updated><title type='text'>An Easier Explanation</title><content type='html'>The &lt;a href="http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96612/d_xplan.htm"&gt;DBMS_XPLAN&lt;/a&gt; supplied package gives results that are so much more usable than the old "set autotrace traceonly explain", or any manual method of reading the plan_table, that the only thing holding me back from using it more often was the &lt;a href="http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96612/d_xplan2.htm"&gt;lengthy syntax&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;No more: I have created views to save my aching fingers. Feel free to use them, modify them, whatever for your own purposes -- just don't blame me if they break something ;)&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;br /&gt;create or replace view xplan_basic&lt;br /&gt;as&lt;br /&gt;select * from table(dbms_xplan.display('plan_table',null,'BASIC'));*&lt;br /&gt;&lt;br /&gt;create or replace view xplan_typical&lt;br /&gt;as&lt;br /&gt;select * from table(dbms_xplan.display('plan_table',null,'TYPICAL'));&lt;br /&gt;&lt;br /&gt;create or replace view xplan_parallel&lt;br /&gt;as&lt;br /&gt;select * from table(dbms_xplan.display('plan_table',null,'ALL'));&lt;br /&gt;&lt;br /&gt;create or replace view xplan_serial&lt;br /&gt;as&lt;br /&gt;select * from table(dbms_xplan.display('plan_table',null,'SERIAL'));&lt;br /&gt;&lt;br /&gt;I am now a mere "select * from xplan_parallel" away from my execution plans.&lt;br /&gt;&lt;br /&gt;* see comment from Pete ... I missed the "BASIC" parameter value in the original post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112541770379765773?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112541770379765773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112541770379765773' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112541770379765773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112541770379765773'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/easier-explanation.html' title='An Easier Explanation'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112541388391486349</id><published>2005-08-30T07:00:00.000-06:00</published><updated>2005-08-30T08:58:03.946-06:00</updated><title type='text'>Partition Pruning and Dimension Tables</title><content type='html'>As a side note to a &lt;a href="http://oraclesponge.blogspot.com/2005/08/execution-plans-for-partition-not.html"&gt;previous blog&lt;/a&gt;, Peter Scott &lt;a href="http://pjs-random.blogspot.com/2005/08/partition-pruning-works.html"&gt;kindly humoured me&lt;/a&gt; by checking on a partition pruning scenario that I had been unable to simulate. Specifically, the scenario is of partition pruning in a fact table based on a predicate that references a higher dimensional level through a joined dimension table.&lt;br /&gt;&lt;br /&gt;Well, I found the metalink note that describes this method of optimization, and it's number &lt;a href="http://metalink.oracle.com/metalink/plsql/ml2_documents.showFrameDocument?p_database_id=NOT&amp;p_id=209070.1"&gt;209070.1&lt;/a&gt;, with the generously proportioned title: "Partition Pruning based on Joins to Partitioning Criteria Stored in Dimension Tables". In contrast to the &lt;a href="http://oraclesponge.blogspot.com/2005/06/most-useless-metalink-article-ever.html"&gt;Most Useless Metalink Article Ever&lt;/a&gt;, this one is actually extremely useful, and aside from skipping details of a couple of hidden parameters it is very detailed in its description of the internal mechanism by which the optimizer implements "subquery pruning". Maybe I'll name it "Most Useful Metalink Article Ever". Nah, maybe not.&lt;br /&gt;&lt;br /&gt;What also aroused my interest was the article's mention of the TBL$OR$IDX$PART$NUM() function, which I'd previously only encountered in trace files for partition exchanges and &lt;a href="http://www.dbazine.com/oracle/or-articles/jlewis17"&gt;an article&lt;/a&gt; by Jonathan Lewis. I guess that this is about as documented as this function gets.&lt;br /&gt;&lt;br /&gt;Another feature, interesting by it's omission, is that foreign keys do not get a mention either in this article or the associated &lt;a href="http://metalink.oracle.com/metalink/plsql/showdoc?db=NOT&amp;amp;amp;amp;amp;id=179518.1&amp;blackframe=1"&gt;179518.1&lt;/a&gt;: "Partition Pruning and Joins". I'll have to see if my tests require a foreign key or not -- Peter's own test used foreign key constraints in the disabled/rely state, and I'm guessing that they're not considered.&lt;br /&gt;&lt;br /&gt;Also worthy of note are the conditions under which subquery pruning will be invoked: "&lt;span style="font-style: italic;"&gt;The cost of the recursive subquery must not exceed 5% of the cost of accessing all data in the partitioned fact table and the predicates on the dimension table must select less than 50% of the data in the dimension table.&lt;/span&gt;" The former appears to be controlled by the hidden parameter _subquery_pruning_cost_factor and the latter by _subquery_pruning_reduction, which have default values of 20 (1/0.05 of course) and 50 respectively on my 10.1.0.3.0 database. Rather circumstantial evidence, but supported by the note's advice:&lt;br /&gt;"&lt;span style="font-style: italic;"&gt;As long as there is a valid join on the partition key then pruning can be forced by setting :&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;         _subquery_pruning_cost_factor =1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;        and&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;         _subquery_pruning_reduction =100. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;This effectively overrides the default choice made by the optimizer.&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;The recursive subquery referred to above appears to be the one by which the required partitions are identified: that involving the TBL$OR$IDX$PART$NUM() function. Since this is a query against a dimension table it is difficult toimagine that it could reach 5% of the total query cost under real world conditions, but it's another issue to bear in mind. I speculatively wonder whether it would be possible to create a materialized view to help return this result faster, or whether the nature of the function or the use of recursive SQL would prohibit it's creation or use? Another thing to think about later.&lt;br /&gt;&lt;br /&gt;Anyway, a little more work could nail these issues down ... alas, tempus fugit etc.&lt;br /&gt;&lt;br /&gt;Finally there is another hidden parameter (revealed through the use of JL's script &lt;a href="http://www.jlcomp.demon.co.uk/params.html"&gt;here&lt;/a&gt;) to consider: _subquery_pruning_mv_enabled, with a default value of "false" and a description of "&lt;span style="font-style: italic;"&gt;enable the use of subquery predicates with MVs to perform pruning&lt;/span&gt;". This seems to me to be a critical parameter. Why it is set to false by default is not immediately clear to me but I'll be keeping this parameter in mind as it appears that it could relate to query rewrite which is an important part of the database design I am working on. Worse case scenario: raising an iTar to get the thumbs up from Oracle Support to make a change to a hidden parameter. Not a bad thing in itself, as they generally like you to jump through a few hoops in justifying such a course of action.&lt;br /&gt;&lt;br /&gt;Well, it's been an interesting and educational week so far, that's for sure.&lt;br /&gt;&lt;br /&gt;For another resource on this issue see &lt;a href="http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:7037864783524"&gt;this thread&lt;/a&gt; at AskTom.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112541388391486349?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112541388391486349/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112541388391486349' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112541388391486349'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112541388391486349'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/partition-pruning-and-dimension-tables.html' title='Partition Pruning and Dimension Tables'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112507466872351362</id><published>2005-08-26T10:43:00.000-06:00</published><updated>2005-08-26T10:44:28.736-06:00</updated><title type='text'>Doings With Dimensions</title><content type='html'>An &lt;a href="http://pjs-random.blogspot.com/2005/08/validation-of-dimensions.html"&gt;interesting blog&lt;/a&gt; over at Peter Scott's place -- BYOB.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112507466872351362?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112507466872351362/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112507466872351362' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112507466872351362'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112507466872351362'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/doings-with-dimensions.html' title='Doings With Dimensions'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112507304119115131</id><published>2005-08-26T10:05:00.000-06:00</published><updated>2005-08-26T11:31:15.530-06:00</updated><title type='text'>Is there anyone out there not on vacation or travel?</title><content type='html'>So, Howard Rogers is &lt;a href="http://www.dizwell.com/2005/08/see-you-later.html"&gt;in New Zealand&lt;/a&gt;, Tom Kyte is &lt;a href="http://tkyte.blogspot.com/2005/08/greetings-from-iceland.html#comments"&gt;in Iceland&lt;/a&gt; (and heading to the rest of Europe), &lt;a href="http://www.jlcomp.demon.co.uk/appearances.html"&gt;Jonathan Lewis&lt;/a&gt; was in Norway yesterday and is in Lithuania next week, and everyone from Burleson Consulting is in an &lt;a href="http://dba-oracle.blogspot.com/2005/08/great-scuba-day.html"&gt;undisclosed location&lt;/a&gt; -- I don't know where it is but it sure ain't North Carolina.&lt;br /&gt;&lt;br /&gt;I get two nights with the family in a travel trailer up in &lt;a href="http://www.fourteenernet.com/buenavista/"&gt;Buena Vista&lt;/a&gt; (pronounced "Byoona Vista" by the locals, it seems). Oh, I'll be in Dayton, Ohio for the &lt;a href="http://afmarathon.wpafb.af.mil/"&gt;Air Force Marathon&lt;/a&gt; next month (no, not me -- the wife is running the half-marathon).&lt;br /&gt;&lt;br /&gt;What exactly am I doing wrong?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112507304119115131?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112507304119115131/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112507304119115131' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112507304119115131'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112507304119115131'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/is-there-anyone-out-there-not-on.html' title='Is there anyone out there not on vacation or travel?'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112507143357848466</id><published>2005-08-26T09:23:00.000-06:00</published><updated>2005-08-26T09:50:33.626-06:00</updated><title type='text'>The Linux Experience: What's Missing</title><content type='html'>It's been a week or two since I dedicated my laptop entirely to Whitebox Linux, and so far I have few complaints.&lt;br /&gt;&lt;br /&gt;There are some applications that I rely on that are either not available on Linux, or for which I don't have a spare $100,000 for the license. In the former category is &lt;a href="http://www.ultraedit.com/index.php?name=Content&amp;pa=showpage&amp;amp;pid=10"&gt;UltraEdit&lt;/a&gt;. It's one of those applications that seem pretty simple to start with, and then you find one key feature that you can't do without. For me that feature is column-mode editing.&lt;br /&gt;&lt;br /&gt;Long-story-short, column-mode editing allows you to select, copy and paste a rectangular block of text. It also allows you to select a single column, start typing, and have whatever you type echoed on every line selected.&lt;br /&gt;&lt;br /&gt;So for example if you want to create a view over a table with fifty columns and you want to wrap every column in an expression such as:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Decode(col1,'   ','N/A',col1) col1,&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;...then you;&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;DESC the table&lt;/li&gt;   &lt;li&gt;paste the result into UltraEdit&lt;/li&gt;   &lt;li&gt;use column mode to select and copy the rectangle that holds the column names&lt;/li&gt;   &lt;li&gt;paste the result over to the right, twice&lt;/li&gt; &lt;/ol&gt; ... and this gives you your list of column names three times, looking something like;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;col1 col1 col1&lt;/span&gt;&lt;br /&gt; &lt;span style="font-style: italic;"&gt;col2 col2 col2&lt;/span&gt;&lt;br /&gt; &lt;span style="font-style: italic;"&gt;col3 col2 col3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You then use column mode to select the gap to the left of the leftmost column of column names (nothing confusing about this example!) and type "Decode(". This gives you:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;Decode(col1 col1 col1&lt;/span&gt;&lt;br /&gt; &lt;span style="font-style: italic;"&gt;Decode(col2 col2 col2&lt;/span&gt;&lt;br /&gt; &lt;span style="font-style: italic;"&gt;Decode(col3 col3 col3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Then you select the gap to the left of the second column of column names, and type ",'   ','N/A'," giving you:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;Decode(col1,'   ','N/A',col1 col1&lt;/span&gt;&lt;br /&gt; &lt;span style="font-style: italic;"&gt; Decode(col2,'   ','N/A',col2 col2&lt;/span&gt;&lt;br /&gt; &lt;span style="font-style: italic;"&gt; Decode(col3,'   ','N/A',col3 col3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Well, you see how this works anyway. Once you get into the swing of things this is very fast and pretty soon you have:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;Decode(col1,'   ','N/A',col1) col1,&lt;/span&gt;&lt;br /&gt; &lt;span style="font-style: italic;"&gt;  Decode(col2,'   ','N/A',col2) col2,&lt;/span&gt;&lt;br /&gt; &lt;span style="font-style: italic;"&gt;  Decode(col3,'   ','N/A',col3) col3,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now you could do the same thing by querying user_tab_columns, but with a complex or lengthy expression I much prefer this way. For example in:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;Decode(LTrim(col1,'0'),'}',0,'A',1,'B',2,zoned_to_number(col1)) col1,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;... I just can't keep track of all of those single quotes that have to be doubled-up.&lt;br /&gt;&lt;br /&gt;It also will search and replace on special characters such as carriage returns very easily, so you can remove occurances of blank lines by replacing "^p^p" with "^p" until they're all gone for example, or get a line break after each comma by replacing commas with ",^p".&lt;br /&gt;&lt;br /&gt;Not ... available ... on ... Linux.&lt;br /&gt;&lt;br /&gt;Ouch.&lt;br /&gt;&lt;br /&gt;Still, if you're on Windows then I recommend it. For $40 I'd give a copy to every DBA and developer (only if they're on Windows, of course. It'd be a bit of a waste otherwise.)&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112507143357848466?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112507143357848466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112507143357848466' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112507143357848466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112507143357848466'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/linux-experience-whats-missing.html' title='The Linux Experience: What&apos;s Missing'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112480191074891374</id><published>2005-08-23T06:57:00.000-06:00</published><updated>2005-08-23T06:58:30.750-06:00</updated><title type='text'>Word Verification for Comments</title><content type='html'>Following a tip by Gabe over at TK's blog, I've turned on word verification for comments to stop the spambots.&lt;br /&gt;&lt;br /&gt;I don't know, I'll kind of miss them in a way ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112480191074891374?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112480191074891374/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112480191074891374' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112480191074891374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112480191074891374'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/word-verification-for-comments.html' title='Word Verification for Comments'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112473068194999140</id><published>2005-08-22T10:48:00.000-06:00</published><updated>2005-08-22T11:27:57.553-06:00</updated><title type='text'>Execution Plans for "Partition Not-Quite-Pruning"</title><content type='html'>This is a followup to &lt;a href="http://oraclesponge.blogspot.com/2005/08/more-on-partition-not-quite-pruning.html"&gt;this&lt;/a&gt; blog, which itself was a followup to &lt;a href="http://oraclesponge.blogspot.com/2005/08/partition-not-quite-pruning.html"&gt;this&lt;/a&gt; one.&lt;span style="font-weight: bold; font-style: italic;"&gt;&lt;br /&gt;&lt;br /&gt;Table Structure&lt;/span&gt;&lt;br /&gt;The table here is called FCT_FSA_MSD_GSD and is composite partitioned on file_load_month and fund_cd. There are about 60 partitions on file_load_month and three subpartitions per partition, of which one holds only fund_cd values of '6C'. A fiscal month is not directly represented in the table, and is defined with a range of values for the date_of_day column.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Indexes&lt;/span&gt;&lt;br /&gt;xie06fct_fsa_msd_gsd: single column bitmap index on FILE_LOAD_MONTH&lt;br /&gt;xie15fct_fsa_msd_gsd: single column bitmap index on DATE_OF_DAY&lt;br /&gt;xie28fct_fsa_msd_gsd: single column bitmap index on FUND_CD&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Explain Plans&lt;/span&gt;&lt;br /&gt;I've edited the plans just to take out the parallelism references that were mucking up the format, and joined lines together where they broke.&lt;br /&gt;&lt;br /&gt;Here's the old form of the query.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;pre&gt;&lt;font&gt;&lt;font&gt;&lt;tt&gt;SQL&gt; select count(*), sum(fiscal_amt) from fct_fsa_msd_gsd&lt;br /&gt;2  where date_of_day between '01-jan-2004' and '31-jan-2004' and&lt;br /&gt;3  fund_cd = '6C'&lt;br /&gt;4  /&lt;br /&gt;&lt;br /&gt;COUNT(*) SUM(FISCAL_AMT)&lt;br /&gt;---------- ---------------&lt;br /&gt;6469727      3521311527&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:41.01&lt;br /&gt;&lt;br /&gt;Execution Plan&lt;br /&gt;----------------------------------------------------------&lt;br /&gt;0      SELECT STATEMENT Optimizer=CHOOSE (Cost=22964 Card=1 Bytes=16)&lt;br /&gt;1    0   SORT (AGGREGATE)&lt;br /&gt;2    1     SORT* (AGGREGATE)&lt;br /&gt;3    2       PARTITION RANGE* (ALL)&lt;br /&gt;4    3         TABLE ACCESS* (BY LOCAL INDEX ROWID) OF 'FCT_FSA_MSD_GSD' (Cost=22964 Card=940684 Bytes=15050944)&lt;br /&gt;5    4           BITMAP CONVERSION* (TO ROWIDS)&lt;br /&gt;6    5             BITMAP AND*&lt;br /&gt;7    6               BITMAP MERGE*&lt;br /&gt;8    7                 BITMAP INDEX* (RANGE SCAN) OF 'XIE15FCT_FSA_MSD_GSD'&lt;br /&gt;9    6               BITMAP INDEX* (SINGLE VALUE) OF 'XIE28FCT_FSA_MSD_GSD'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Statistics&lt;br /&gt;----------------------------------------------------------&lt;br /&gt;     20  recursive calls&lt;br /&gt;      3  db block gets&lt;br /&gt;  36489  consistent gets&lt;br /&gt;  36360  physical reads&lt;br /&gt;   1016  redo size&lt;br /&gt;    258  bytes sent via SQL*Net to client&lt;br /&gt;    274  bytes received via SQL*Net from client&lt;br /&gt;      2  SQL*Net roundtrips to/from client&lt;br /&gt;     70  sorts (memory)&lt;br /&gt;      0  sorts (disk)&lt;br /&gt;&lt;br /&gt;      1  rows processed&lt;br /&gt;&lt;br /&gt;Commentary on above: A bitmap merge combines&lt;br /&gt;the fund code and date of day predicates,&lt;br /&gt;then every partition of the table is accessed by&lt;br /&gt;rowid.&lt;br /&gt;&lt;span style="font-family:georgia,serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/tt&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;font&gt;&lt;font&gt; &lt;/span&gt;&lt;/span&gt;&lt;pre&gt;&lt;font&gt;&lt;font&gt;&lt;tt&gt;Here's the first part of the improved query&lt;br /&gt;&lt;br /&gt;SQL&gt; select count(*), sum(fiscal_amt) from fct_fsa_msd_gsd&lt;br /&gt;2  where date_of_day between '01-jan-2004' and '31-jan-2004' and&lt;br /&gt;3  fund_cd = '6C' and&lt;br /&gt;4  file_load_month = '01-jan-2004'&lt;br /&gt;5  /&lt;br /&gt;&lt;br /&gt;COUNT(*) SUM(FISCAL_AMT)&lt;br /&gt;---------- ---------------&lt;br /&gt;6469717      3521307863&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:12.02&lt;br /&gt;&lt;br /&gt;Execution Plan&lt;br /&gt;----------------------------------------------------------&lt;br /&gt;0      SELECT STATEMENT Optimizer=CHOOSE (Cost=197 Card=1 Bytes=25)&lt;br /&gt;1    0   SORT (AGGREGATE)&lt;br /&gt;2    1     SORT* (AGGREGATE)&lt;br /&gt;3    2       TABLE ACCESS* (FULL) OF 'FCT_FSA_MSD_GSD' (Cost=197 Card=3375101 Bytes=84377525)&lt;br /&gt;&lt;br /&gt;Statistics&lt;br /&gt;----------------------------------------------------------&lt;br /&gt;    149  recursive calls&lt;br /&gt;      3  db block gets&lt;br /&gt;  37043  consistent gets&lt;br /&gt;  36651  physical reads&lt;br /&gt;    936  redo size&lt;br /&gt;    244  bytes sent via SQL*Net to client&lt;br /&gt;    275  bytes received via SQL*Net from client&lt;br /&gt;      2  SQL*Net roundtrips to/from client&lt;br /&gt;      3  sorts (memory)&lt;br /&gt;      0  sorts (disk)&lt;br /&gt;      1  rows processed&lt;br /&gt;&lt;br /&gt;Commentary on above: This is 9.2.0.6 and the explain plan is not&lt;br /&gt;showing that partition pruning has taken place.&lt;br /&gt;However from the consistent gets and physical reads is evidently has.&lt;br /&gt;Looks like the subpartition stats are off as well. Tut.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here's the second part of the improved query&lt;br /&gt;&lt;br /&gt;SQL&gt; select count(*),sum(fiscal_amt) from fct_fsa_msd_gsd&lt;br /&gt;2  where date_of_day between '01-jan-2004' and '31-jan-2004' and&lt;br /&gt;3  fund_cd = '6C' and&lt;br /&gt;4  file_load_month != '01-jan-2004'&lt;br /&gt;5  /&lt;br /&gt;&lt;br /&gt;COUNT(*) SUM(FISCAL_AMT)&lt;br /&gt;---------- ---------------&lt;br /&gt;    10          3663.2&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:04.00&lt;br /&gt;&lt;br /&gt;Execution Plan&lt;br /&gt;----------------------------------------------------------&lt;br /&gt;0      SELECT STATEMENT Optimizer=CHOOSE (Cost=22432 Card=1 Bytes=24)&lt;br /&gt;1    0   SORT (AGGREGATE)&lt;br /&gt;2    1     SORT* (AGGREGATE)&lt;br /&gt;3    2       PARTITION RANGE* (ALL)&lt;br /&gt;4    3         TABLE ACCESS* (BY LOCAL INDEX ROWID) OF 'FCT_FSA_MSD_GSD' (Cost=22432 Card=919682 Bytes=22072368)&lt;br /&gt;5    4           BITMAP CONVERSION* (TO ROWIDS)&lt;br /&gt;6    5             BITMAP AND*&lt;br /&gt;7    6               BITMAP MINUS*&lt;br /&gt;8    7                 BITMAP MERGE*&lt;br /&gt;9    8                   BITMAP INDEX* (RANGE SCAN) OF 'XIE15FCT_FSA_MSD_GSD'&lt;br /&gt;10    7                 BITMAP INDEX* (SINGLE VALUE) OF 'XIE06FCT_FSA_MSD_GSD'&lt;br /&gt;11    6               BITMAP INDEX* (SINGLE VALUE) OF 'XIE28FCT_FSA_MSD_GSD'&lt;br /&gt;&lt;br /&gt;Statistics&lt;br /&gt;----------------------------------------------------------&lt;br /&gt;     20  recursive calls&lt;br /&gt;      3  db block gets&lt;br /&gt;    725  consistent gets&lt;br /&gt;    591  physical reads&lt;br /&gt;   1008  redo size&lt;br /&gt;    253  bytes sent via SQL*Net to client&lt;br /&gt;    275  bytes received via SQL*Net from client&lt;br /&gt;      2  SQL*Net roundtrips to/from client&lt;br /&gt;     70  sorts (memory)&lt;br /&gt;      0  sorts (disk)&lt;br /&gt;      1  rows processed&lt;br /&gt;&lt;br /&gt;Commentary on above. Bitmap indexes on file_load_month is minus'd&lt;br /&gt;from that on date_of_day, then the result is merged with that on&lt;br /&gt;fund cd, and the entire table is accessed by rowid.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here's the combined parts of the improved query&lt;br /&gt;&lt;br /&gt;SQL&gt; select sum(rc),sum(fiscal_amt) from&lt;br /&gt;2  (&lt;br /&gt;3  select count(*) rc, sum(fiscal_amt) fiscal_amt from fct_fsa_msd_gsd&lt;br /&gt;4  where date_of_day between '01-jan-2004' and '31-jan-2004' and&lt;br /&gt;5  fund_cd = '6C' and&lt;br /&gt;6  file_load_month = '01-jan-2004'&lt;br /&gt;7  union all&lt;br /&gt;8  select count(*),sum(fiscal_amt) from fct_fsa_msd_gsd&lt;br /&gt;9  where date_of_day between '01-jan-2004' and '31-jan-2004' and&lt;br /&gt;10  fund_cd = '6C' and&lt;br /&gt;11  file_load_month != '01-jan-2004'&lt;br /&gt;12  )&lt;br /&gt;13  /&lt;br /&gt;&lt;br /&gt;SUM(RC) SUM(FISCAL_AMT)&lt;br /&gt;---------- ---------------&lt;br /&gt;6469727      3521311527&lt;br /&gt;&lt;br /&gt;Elapsed: 00:00:37.03&lt;br /&gt;&lt;br /&gt;Execution Plan&lt;br /&gt;----------------------------------------------------------&lt;br /&gt;0      SELECT STATEMENT Optimizer=CHOOSE (Cost=22629 Card=1 Bytes=26)&lt;br /&gt;1    0   SORT (AGGREGATE)&lt;br /&gt;2    1     VIEW (Cost=22629 Card=2 Bytes=52)&lt;br /&gt;3    2       UNION-ALL&lt;br /&gt;4    3         SORT (AGGREGATE)&lt;br /&gt;5    4           SORT* (AGGREGATE)&lt;br /&gt;6    5             TABLE ACCESS* (FULL) OF 'FCT_FSA_MSD_GSD' (Cost=197 Card=3375101 Bytes=84377525)&lt;br /&gt;7    3         SORT (AGGREGATE)&lt;br /&gt;8    7           SORT* (AGGREGATE)&lt;br /&gt;9    8             PARTITION RANGE* (ALL)&lt;br /&gt;10    9               TABLE ACCESS* (BY LOCAL INDEX ROWID) OF 'FCT_FSA_MSD_GSD' (Cost=22432 Card=919682 Bytes=22072368)&lt;br /&gt;11   10                 BITMAP CONVERSION* (TO ROWIDS)&lt;br /&gt;12   11                   BITMAP AND*&lt;br /&gt;13   12                     BITMAP MINUS*&lt;br /&gt;14   13                       BITMAP MERGE*&lt;br /&gt;15   14                         BITMAP INDEX* (RANGE SCAN) OF 'XIE15FCT_FSA_MSD_GSD'&lt;br /&gt;16   13                       BITMAP INDEX* (SINGLE VALUE) OF 'XIE06FCT_FSA_MSD_GSD'&lt;br /&gt;17   12                     BITMAP INDEX* (SINGLE VALUE) OF 'XIE28FCT_FSA_MSD_GSD'&lt;br /&gt;&lt;br /&gt;Commentary on above: Here we go, all working nicely together. the timing&lt;br /&gt;for this combined query is high, but this is a working production&lt;br /&gt;machine with a bunch of other stuff going on.&lt;br /&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;&lt;font&gt;&lt;font&gt;Other Comments&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;font&gt;&lt;font&gt;&lt;br /&gt;My guesstimate on the row proportions was off. In fact there were 6.5 million rows involved in the result set, and only 10 of them were not in the Jan 2005 partition (so that's 0.000154%).&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112473068194999140?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112473068194999140/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112473068194999140' title='19 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112473068194999140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112473068194999140'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/execution-plans-for-partition-not.html' title='Execution Plans for &quot;Partition Not-Quite-Pruning&quot;'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>19</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112463901918673426</id><published>2005-08-21T05:17:00.000-06:00</published><updated>2005-08-21T17:17:46.453-06:00</updated><title type='text'>More on Partition Not-Quite-Pruning</title><content type='html'>&lt;span style="font-style: italic;"&gt;(Updated below)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here's a follow up to the &lt;a href="http://oraclesponge.blogspot.com/2005/08/partition-not-quite-pruning.html"&gt;previous post&lt;/a&gt; on this subject, which ought to be read first. This is just to give more background on why I think this technique works.&lt;br /&gt;&lt;br /&gt;We have a scenario where we want to read all of the rows where fiscal_month is Jan-2005 (around one million rows) from a fact table of sixty partitions (based on file_load_month). 99.5% of these rows (995,000 rows) are contained in a single partition (file_load_month=Jan-2005) which itself holds around one million rows. The other 5,000 rows are scattered across other partitions of the table. In fact they will probably be found in around ten-twenty of the remaining fifty-nine partitions.&lt;br /&gt;&lt;br /&gt;If you just query for rows where "fiscal_month = Jan-2005" then no partition pruning is possible (remember that the table is partitioned on file_load_month) and therefore the optimizer has two choices on how to execute this&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Access by index -- find several million rows by reading a bitmap index on fiscal_month and then reading the relevant blocks through single block io.&lt;/li&gt;   &lt;li&gt;Access by full table scan -- read all sixty partitions of the table in multiblock io.&lt;/li&gt; &lt;/ol&gt; Neither of these are satisfactory, so a different query was employed where two queries were UNION ALL'd together.&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Selects all of the required rows from the file_load_month Jan-2005 partition&lt;/li&gt;   &lt;li&gt;Select all of the required rows from all of the other partitions.&lt;/li&gt; &lt;/ol&gt; The first query uses partition pruning to read 995,000 rows of the one million rows in the file_load_month Jan-2005 partition. Multiblock io is used.&lt;br /&gt;&lt;br /&gt;The second query accesses the table through a BITMAP MINUS operation on two bitmap indexes (on fiscal_month minus file_load_month) to read around 5,000 rows that are probably scattered throughout the remaining fifty-nine partitions using single block io.&lt;br /&gt;&lt;br /&gt;Now if you consider how many blocks get read for the old technique and the new technique, then the two methods are practically the same. In fact the new method probably reads slightly more blocks than the old method. The difference between them comes from the ability of the new methodology to read nearly all of the required table blocks in multiblock mode.&lt;br /&gt;&lt;br /&gt;It is interesting to note that the optimizer actually has all of the information that it needs in order to perform this optimization internally. Partition-level histograms on the fiscal_month show that nearly all of the required rows are contained in a single partition, and almost none of them are contained in any other.&lt;br /&gt;&lt;br /&gt;I'm going to get some explain plans extracted that are more instructive than those I currently have, and I'll get back to you with them.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Update&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Jonathan Lewis has written to point out the similarity between this approach and the practically-defunct feature of "Partition Views" (PV), in which similar tables are UNION ALL'ed together in a view that can be queried to produce an effect similar to pruning in a partitioned table (PT).&lt;br /&gt;&lt;br /&gt;He also points out one of the strengths of PV -- that the optimizer could not only decide not to touch a partition (a form of optimization we know as "pruning" of course) but could also generate a different form of execution plan for each partition that the query would touch. This is a benefit of PV that was lost with PT (except for the "do not touch this partition" pruning optimization) and which is resurrected in the technique I'm describing here. Exactly the same principle applies, of breaking up a result set into multiple subsets with UNION ALL to merge them together.&lt;br /&gt;&lt;br /&gt;I'm inclined to wonder whether in this particular example an approach of defining a partition view over a partitioned table, in the form of ...&lt;br /&gt;&lt;br /&gt;Select fiscal_month, file_load_month, ...&lt;br /&gt;from my_table&lt;br /&gt;where fiscal_month = file_load_month&lt;br /&gt;Union All&lt;br /&gt;Select fiscal_month, file_load_month, ...&lt;br /&gt; from my_table&lt;br /&gt; where fiscal_month != file_load_month&lt;br /&gt;&lt;br /&gt;... would be productive. I wonder whether the optimizer transitivity would be robust enough to handle this situation.&lt;br /&gt;&lt;br /&gt;Jonathan's article comparing PV and PT is in Microsoft Word format &lt;a href="http://www.jlcomp.demon.co.uk/pvorpt.doc"&gt;here&lt;/a&gt; -- for the MS-averse Google has a passable HTML conversion &lt;a href="http://66.102.7.104/search?q=cache:odQMdwX9lXkJ:www.jlcomp.demon.co.uk/pvorpt.doc"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112463901918673426?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112463901918673426/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112463901918673426' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112463901918673426'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112463901918673426'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/more-on-partition-not-quite-pruning.html' title='More on Partition Not-Quite-Pruning'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112455220762423441</id><published>2005-08-20T09:21:00.000-06:00</published><updated>2005-08-21T09:44:45.116-06:00</updated><title type='text'>Partition Not-Quite-Pruning</title><content type='html'>I'm in the middle of a migration of a fact table from one structure to another. The key difference is in the partitioning key -- the old structure was partitioned according to the month in which the data arrived, wheras the new structure is partitioned according to the fiscal month of the transaction. It's a very slight but very important difference, because it is the fiscal month that the users will query by, hence partition pruning is very much more likely to occur in the new structure.&lt;br /&gt;&lt;br /&gt;The data is being migrated one new-table partition at a time, to allow MV maintenance-without-tears. Now a partition of the new table sources data almost entirely from one partition of the old table, but not quite. Probably around 99.5% of the new partition's data will come from a single partition of the old table (and will represent about 99.5% of that old partition's data). The other 0.5% can come from pretty much any other partition of the old table.&lt;br /&gt;&lt;br /&gt;So, here's the problem -- does the optimizer scan the entire old table in lovely efficient multiblock reads (direct, reads, because of the query parallelism), or does it use single block reads and the bitmap index on fiscal_month? Either one of these is unsatisfactory, so here's the solution I came up with.&lt;br /&gt;&lt;br /&gt;Instead of the straightforward statement:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Select *&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family:courier new;"&gt;From  old_table&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family:courier new;"&gt;Where fiscal_month = '01-jan-2005'&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;br /&gt;... we instead can use:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Select *&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;From  old_table&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Where fiscal_month = '01-jan-2005' and&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;file_load_month &lt;span style="font-weight: bold;"&gt;=&lt;/span&gt; '01-jan-2005'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Union All&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Select *&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; From  old_table&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; Where fiscal_month = '01-jan-2005' and&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; file_load_month &lt;span style="font-weight: bold;"&gt;!=&lt;/span&gt; '01-jan-2005'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first result set selects the 99.5% of the required rows that represent 99.5% of the old tables file_load_month-based partition for '01-jan-2004', and it does this with an efficient (multiblock) full scan of a single partition.&lt;br /&gt;&lt;br /&gt;The second result set selects the 0.5% of the required rows that are in any partition other than that for file_load_month '01-jan-2004', and it does this with single block reads through the combination of the bitmap indexes on fiscal_month and file_load_month.&lt;br /&gt;&lt;br /&gt;So in this case we got the best of both worlds. The query time dropped from around 56 seconds to 17 seconds.&lt;br /&gt;&lt;br /&gt;Now, what should we call this? "Partition Not-Quite-Pruning"? "Partition Semipruning?" ... ?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Continued &lt;a href="http://oraclesponge.blogspot.com/2005/08/more-on-partition-not-quite-pruning.html"&gt;here&lt;/a&gt; ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112455220762423441?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112455220762423441/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112455220762423441' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112455220762423441'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112455220762423441'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/partition-not-quite-pruning.html' title='Partition Not-Quite-Pruning'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112359984989979037</id><published>2005-08-18T04:30:00.000-06:00</published><updated>2005-08-23T18:22:19.703-06:00</updated><title type='text'>A List: Moving Data Between Databases</title><content type='html'>A simple one, this. But there's a lot of ways out there.&lt;br /&gt;&lt;ol&gt;   &lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b12170/ch13.htm#sthref2969"&gt;Spool&lt;/a&gt; to Flat File, Load with &lt;/span&gt;&lt;a style="font-style: italic;" href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10825/part_ldr.htm"&gt;SQL*Loader&lt;/a&gt;&lt;span style="font-style: italic;"&gt; or &lt;/span&gt;&lt;a style="font-style: italic;" href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10825/dp_overview.htm#sthref19"&gt;External Tables&lt;/a&gt;&lt;span style="font-style: italic;"&gt;:&lt;/span&gt; SQL*Plus does a reasonable job of unloading. Tom Kyte has a &lt;a href="http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:459020243348"&gt;C utility&lt;/a&gt; for unloading data also.&lt;/li&gt;   &lt;li&gt;&lt;a style="font-style: italic;" href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b12170/apb.htm#BGBGGEIC"&gt;SQL*Plus COPY command&lt;/a&gt;&lt;span style="font-style: italic;"&gt;:&lt;/span&gt; Sadly deprecated, and without support for all data types, but a handy tool for basic data transfers. Allows arbitrary SQL on the data selection.&lt;/li&gt;   &lt;li&gt;&lt;a style="font-style: italic;" href="http://otn.oracle.com/pls/db10g/db10g.to_URL?remark=drilldown&amp;urlname=http:%2F%2Fdownload-west.oracle.com%2Fdocs%2Fcd%2FB14117_01%2Fserver.101%2Fb10759%2Fstatements_5005.htm%23SQLRF01205"&gt;Database Links&lt;/a&gt;&lt;span style="font-style: italic;"&gt;:&lt;/span&gt; Direct movement from one database to another. Aside from the network latency this is basically the same as reading data from your local database. If you combine database links and materialized views, then you can replicate remote data to your local database through the databae link.&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;&lt;a style="font-style: italic;" href="http://otn.oracle.com/pls/db10g/db10g.to_URL?remark=drilldown&amp;urlname=http:%2F%2Fdownload-west.oracle.com%2Fdocs%2Fcd%2FB14117_01%2Fappdev.101%2Fb10807%2F09_packs.htm%23sthref1153"&gt;DBMS_PIPE&lt;/a&gt;&lt;span style="font-style: italic;"&gt;:&lt;/span&gt; I don't recall reading of anyone using this, but I expect that it's a theoretical possibility to send data from one instance to another through a pipe. &lt;span style="color: rgb(255, 0, 0);"&gt;scratch this one: see TK's comment&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;&lt;a style="font-style: italic;" href="http://otn.oracle.com/pls/db10g/db10g.show_toc?which=main&amp;partno=b10825&amp;amp;maxlevel=2&amp;section=&amp;amp;expand=44975"&gt;Export/Import&lt;/a&gt;&lt;span style="font-style: italic;"&gt;:&lt;/span&gt; Sometimes mistaken for part of a backup and recovery strategy!&lt;/li&gt;   &lt;li&gt;&lt;a style="font-style: italic;" href="http://otn.oracle.com/pls/db10g/db10g.show_toc?which=main&amp;partno=b10825&amp;amp;maxlevel=2&amp;section=&amp;amp;expand=45122"&gt;Transportable Tablespaces:&lt;/a&gt; Closely related to Export/Import, allowing movement of entire tablespaces without the need for unloading and reloading data.&lt;/li&gt;   &lt;li&gt;&lt;a style="font-style: italic;" href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10825/part_dp.htm#i436481"&gt;Data Pump&lt;/a&gt;: Export/Import for the new millenium :) and with many &lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10825/dp_overview.htm#i1010248"&gt;new features&lt;/a&gt;.&lt;/li&gt;   &lt;li&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10743/intro.htm#sthref234"&gt;&lt;span style="font-style: italic;"&gt;Oracle Streams&lt;/span&gt;&lt;/a&gt;: Powerful functionality here. Non-trivial, but probably the modern tool of choice for the regular propagation of data around your corporate network.&lt;br /&gt;&lt;/li&gt; &lt;/ol&gt; Finally, &lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10743/integrat.htm#g17962"&gt;here&lt;/a&gt; is an introduction to the sharing of information between database systems.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112359984989979037?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112359984989979037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112359984989979037' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112359984989979037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112359984989979037'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/list-moving-data-between-databases.html' title='A List: Moving Data Between Databases'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112428534583117262</id><published>2005-08-17T07:27:00.000-06:00</published><updated>2005-08-18T13:06:38.896-06:00</updated><title type='text'>Physics Review</title><content type='html'>Not an Oracle topic, but here is a news story of interest to the scientifically inclined reader. Science is truly on the defense.&lt;br /&gt;&lt;br /&gt;http://www.theonion.com/news/index.php?issue=4133&amp;amp;n=2&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112428534583117262?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112428534583117262/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112428534583117262' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112428534583117262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112428534583117262'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/physics-review.html' title='Physics Review'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112414304051674091</id><published>2005-08-15T17:00:00.000-06:00</published><updated>2005-08-17T09:37:36.296-06:00</updated><title type='text'>A List: Things That Materialized Views Can Be (Philisophically) Similar To</title><content type='html'>When is a materialized view like a ... ?:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;&lt;span style="font-style: italic;"&gt;Constraint:&lt;/span&gt; When you use it to enforce a multirow constraint, such as "SUM(allocation_pct) per Site = 100", which is not supported through regular constraints. Better then triggers because MV's refresh on commit, not on DDLoperations themselves.&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;&lt;span style="font-style: italic;"&gt;Index:&lt;/span&gt; When you use it to speed a full scan of a subset of a table's columns .&lt;/li&gt;   &lt;li&gt;&lt;span style="font-style: italic;"&gt;Partition:&lt;/span&gt; When a materialized view selects a subset of a table's rows, thus making the subset accessible through multiblock reads instead of single block index-based access, and without requiring the whole of the original table to be scanned.&lt;/li&gt;   &lt;li&gt;&lt;span style="font-style: italic;"&gt;New Set Of Unbelievably Fast Disks:&lt;/span&gt; When a materialized view with query rewrite allows a large data set to be pre-aggregated and subsequently queried in almost no time at all.&lt;/li&gt;   &lt;li&gt;&lt;span style="font-style: italic;"&gt;Trigger:&lt;/span&gt; When you stop trying to enforce multirow constraints with triggers and start using materialized views instead.&lt;/li&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Synonym&lt;/span&gt;: When it allows you to give an alternative name to a table.&lt;/li&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Time Machine:&lt;/span&gt; When a stale materialized view shows you the previous state of a table's data. A materliazed view log then gives you an audit trail of sorts for changes since the last refresh*&lt;br /&gt;  &lt;/li&gt;  &lt;/ol&gt;1, 3 and 4 seem to be the most interesting ones there. I don't think I'd use 2, unless it was on a single column with nulls, and a bitmap index was not appropriate, and the query had to consider nulls. 6 seems like a real stretch.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;* Thanks &lt;a href="http://www.blogger.com/profile/9499100"&gt;Gary&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112414304051674091?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112414304051674091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112414304051674091' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112414304051674091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112414304051674091'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/list-things-that-materialized-views.html' title='A List: Things That Materialized Views Can Be (Philisophically) Similar To'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112412941730773476</id><published>2005-08-15T00:00:00.000-06:00</published><updated>2005-08-16T06:55:05.126-06:00</updated><title type='text'>Training and Demonstrations</title><content type='html'>A few years ago some collegues of mine introduced themselves to a Vice-President of Sales for a Well Known Business Intelligence corporation at a local trade fare, and explained that they were familiar with his product thorugh a "cook-off" that our group had held between his product and that of a major competitior. "Ah ha", cries he, "is that British bastard here as well then?"&lt;br /&gt;&lt;br /&gt;Heh heh heh. It had been an interesting exercise all right. It had culminated in a demonstration to users of the two product suites, with my own demonstration of Product A facing off against the corporation's pre-sales consultant's demonstration of Product B, followed by a round of discussion and voting by the users and project managers. Product A swept the board and was duly annointed the successor to our then-current tool. Apparantly there then followed much gnashing and grinding of teeth at the WKBI corporation, and a belief that the competition had been unfairly skewed in some way.&lt;br /&gt;&lt;br /&gt;So why the overwhelming vote for Product A? The users believed that the product was more intuitive, easier to use, with a more simple interface. They believed that it would just be easier to get their jobs done with that choice. Whether they were right or not, I'm not sure. The difference between theusability of the two products is probably pretty slight, but the difference between the demonstations was very clear and is very well illustrated by the &lt;a href="http://www.computerworld.com/developmenttopics/development/story/0,10801,103905,00.html"&gt;article&lt;/a&gt; at ComputerWorld that prompted today's stream of consciousness. I'll just pause while you absorb it.&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;The two demonstrations were almost exactly like those example methodologies. While the pre-sales consultant for Product B described every feature available to the users, your humble correspondant showed them how to login to Product A, how to run one of the standard reports, how to create and modify a personal report (once at demonstrate-and-explain-every-mouse-click speed, then at normal user speed), and how to send it to other users. It was a very *ahem* dynamic presentation with a great deal of audience interaction. I suppose that the essence of the matter was that a sales demonstration was turned into a training session of the type described in the article.&lt;br /&gt;&lt;br /&gt;So the end result was that the audience saw that Product A did what they want, but that Product B did a lot of stuff that they didn't fully comprehend. From there the voting was practically a formality.&lt;br /&gt;&lt;br /&gt;I wonder whether the Well Known Business Intelligence corporation's consultant ever realised why the bid was lost to them? The VP of Sales certainly had a strong opinions on the matter. The big baby.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112412941730773476?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112412941730773476/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112412941730773476' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112412941730773476'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112412941730773476'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/training-and-demonstrations.html' title='Training and Demonstrations'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112379425426823167</id><published>2005-08-11T15:02:00.000-06:00</published><updated>2005-08-11T15:04:14.283-06:00</updated><title type='text'>How Not To Ask A Question</title><content type='html'>Do you think it's possible that this questioner is being just a little broad in the advice he/she is &lt;a href="http://dba.ipbhost.com/index.php?showtopic=2410"&gt;requesting&lt;/a&gt;? Maybe just a shade optimistic?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112379425426823167?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112379425426823167/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112379425426823167' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112379425426823167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112379425426823167'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/how-not-to-ask-question.html' title='How Not To Ask A Question'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112378863279737024</id><published>2005-08-11T13:28:00.000-06:00</published><updated>2005-08-11T13:30:32.983-06:00</updated><title type='text'>Lesson from the Shark Tank</title><content type='html'>&lt;a href="http://www.computerworld.com/departments/opinions/sharktank/0,4885,103826,00.html"&gt;Here&lt;/a&gt; are two learning experiences in one -- how databases get corrupted, and how consultants get ... um ... corrupted as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112378863279737024?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112378863279737024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112378863279737024' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112378863279737024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112378863279737024'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/lesson-from-shark-tank.html' title='Lesson from the Shark Tank'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112377059219195768</id><published>2005-08-11T08:23:00.000-06:00</published><updated>2005-08-11T08:29:52.193-06:00</updated><title type='text'>Waiting For A Delivery</title><content type='html'>If there's anything more exciting than waiting for the delivery of a shiny new piece of technology, then I'd like to know what it is.&lt;br /&gt;&lt;br /&gt;Today I'm waiting for a replacement hard drive for my two year old laptop, which I'm going to store in the basement as a little database and HTML DB server, on my "shelf of technology" (cable modem, wireless router, NSLU2 and attached hard drive). The new drive is a speedy little &lt;a href="http://www.hitachigst.com/portal/site/en/menuitem.c8c3966a526cfb5deb4703e3aac4f0a0/"&gt;Hitachi Travelstar 7K60&lt;/a&gt;, which seems to be about the fastest I can get. A bit tricky to come by, but I found one &lt;a href="http://www.outpost.com/"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So I'm really changing the drive because if it all goes pear-shaped and I want to get my old WinXP/Suse9.1 dual-boot laptop back then I can just swap the disks over again. That, and it's a shiny new thing that I get delivered, and sometimes you just have to find excitement where you can.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112377059219195768?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112377059219195768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112377059219195768' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112377059219195768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112377059219195768'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/waiting-for-delivery.html' title='Waiting For A Delivery'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112368388736199734</id><published>2005-08-10T08:00:00.000-06:00</published><updated>2005-08-10T09:38:28.380-06:00</updated><title type='text'>A List: Ways to Scan a Table Faster</title><content type='html'>So you need to read an entire table? Here's some features and techniques that may help.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96524/c20paral.htm#22669"&gt;Employ Parallelism&lt;/a&gt;: Ah, the sweetest technique of all. Brute force. If you have the resources, then let Oracle divide the table into chunks and use all your system resources to scan it. Unfriendly in an OLTP environment, mind you.&lt;br /&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10743/schema.htm#sthref723"&gt;Compress Data Segments&lt;/a&gt;: Make the table smaller! Block level compression can shrink that data like a plunge into cold water. &lt;span style="font-style: italic;"&gt;Very&lt;/span&gt; OLTP unfriendly.&lt;br /&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10743/logical.htm#sthref316"&gt;Reduce Free Space Percent&lt;/a&gt;: PCTFREE = very small =&gt; more rows per block =&gt; smaller table. And potentially a higher chance of row migration, of course.&lt;br /&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10743/logical.htm#sthref316"&gt;Increase Percent Used&lt;/a&gt;: PCTUSED = large =&gt; less likely that blocks retain free space following deletes =&gt; more rows per block =&gt; smaller table.&lt;br /&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96524/c03block.htm#2595"&gt;Use a Larger Block Size&lt;/a&gt;: For significantly long rows you may get reduced empty space, thus a smaller table to scan.&lt;br /&gt;Reorder The Columns: If you are commonly interested in just a subset of columns (for example metrics in a fact table) then consider making them the first columns of the table definition - for tables with lots of columns there is measurable overhead in finding the end columns (I'm not talking about row chaining here). Hmmm, maybe I'll post something else about this.&lt;br /&gt;&lt;a href="http://asktom.oracle.com/pls/ask/f?p=4950:8:::::F4950_P8_DISPLAYID:6644794950373#6657887690948"&gt;Index Columns of Interest&lt;/a&gt;: An index can be treated as a skinny table, and your query might be satisfied by a fast ful or full index scan. The usual comments about NULL values in indexes apply here. Don't neglect consideraton of index size either - index key compression and use of bitmap indexes provide smaller structures to scan.&lt;br /&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96524/c11schem.htm#18094"&gt;Materialized Views&lt;/a&gt;: Is there anything they're not good for? This could be a genuine skinny table, or an aggregation of selected columns.&lt;br /&gt;Ensure Table Is Spread Over Available Devices: With consequent reduced likelihood of encountering an i/o choke point.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;There is not a single feature listed here that carries with it no disadvantages, and depending on your circumstances the severity of the disadvantages may range from the insignificant to the devastating.&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Do not implement any of these without understanding how the feature works, the mechanism by which it provides the advantage, how it brings disadvantages, and how these all interact in your particular situation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112368388736199734?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112368388736199734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112368388736199734' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112368388736199734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112368388736199734'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/list-ways-to-scan-table-faster.html' title='A List: Ways to Scan a Table Faster'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112355670886456821</id><published>2005-08-09T11:03:00.000-06:00</published><updated>2005-08-09T11:34:28.940-06:00</updated><title type='text'>Handy Hardware, Or Not ...</title><content type='html'>&lt;a href="http://www.anandtech.com/storage/showdoc.aspx?i=2480"&gt;Here&lt;/a&gt;'s an AnandTech review that caught my eye -- 4Gb of memory with a battery backup. Could this be an economical way of getting performance for non-sequential storage access?&lt;br /&gt;&lt;br /&gt;I wasn't particularly impressed with the way that the performance was reported, particularly for the random access test, because no indication was given on whether the device was the bottleneck on the test or not -- hey, maybe the CPU's were maxed out? It's a mystery. There's an indication &lt;a href="http://www.hkepc.com/hwdb/iramdisk-gbt-5.htm"&gt;here&lt;/a&gt; that random reads and writes would really benefit.&lt;br /&gt;&lt;br /&gt;So what do you think? I'm no shill for solid-state drives, but for a small-but-busy server, would you put your redo logs on this? Temp space? How about the system tablespace? ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112355670886456821?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112355670886456821/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112355670886456821' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112355670886456821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112355670886456821'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/handy-hardware-or-not.html' title='Handy Hardware, Or Not ...'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112356226689004582</id><published>2005-08-08T23:59:00.000-06:00</published><updated>2005-08-09T06:50:37.483-06:00</updated><title type='text'>A List: SQL Features You've Probably Never Used In Production</title><content type='html'>By popular demand (one anonymous person -- hey, it's all relative), another list.&lt;br /&gt;&lt;br /&gt;OK, you may have played with them, found a hypothetical circumstance for them, but you've probably never found a real situation in which to use them, or if you have you've probably backed out at the last minute. Or the DBA won't let you use them. Or you found there was a bug that spoiled it.&lt;br /&gt;&lt;br /&gt;More likely you will not even recognize them -- unless you're one of those losers who enjoys browsing documentation of course. * ahem *&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10759/statements_10002.htm#i2161315"&gt;The Subquery Factoring Clause&lt;/a&gt;: OK, a bit of a softball to start with. I bet that someone has used this. Not first time, but as part of a tuning exercise. And to show off.&lt;br /&gt; &lt;/li&gt;   &lt;li&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10759/statements_10002.htm#i2161315"&gt;The Partitioning Clause of a Query Table Expression&lt;/a&gt;: Actually hardcoding a partition name in a query? Wellll, OK maybe.&lt;br /&gt; &lt;/li&gt;   &lt;li&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B14117_01/server.101/b10759/statements_10002.htm#i2172805"&gt;The Model Clause&lt;/a&gt;: This is great! What's it for?&lt;/li&gt;   &lt;li&gt;&lt;a href="http://oraclesvca2.oracle.com/docs/cd/B14117_01/server.101/b10759/operators006.htm#sthref776"&gt;Multiset Operators&lt;/a&gt;: Or nested tables in general&lt;/li&gt;   &lt;li&gt;&lt;a href="http://oraclesvca2.oracle.com/docs/cd/B14117_01/server.101/b10759/conditions019.htm#sthref1003"&gt;Submultiset&lt;/a&gt;: OK, that's cheating. Let's just say "nested tables"&lt;/li&gt;   &lt;li&gt;&lt;a href="http://oraclesvca2.oracle.com/docs/cd/B14117_01/server.101/b10759/functions025.htm#sthref1179"&gt;The CORR_K() Function&lt;/a&gt;: Oh wait, there was that time when ... nah not really. Never used it.&lt;/li&gt;   &lt;li&gt;&lt;a href="http://oraclesvca2.oracle.com/docs/cd/B14117_01/server.101/b10759/functions104.htm#sthref1555"&gt;PowerMultiset_By_Cardinality&lt;/a&gt;: "&lt;span style="font-style: italic;"&gt;...takes as input a nested table and a cardinality and returns a nested table of nested tables containing all nonempty subsets (called submultisets) of the nested table of the specified cardinality&lt;/span&gt;". * wipes-eyes * OK seriously, that's the last time I'm going to mention nested tables. Or nested tables of nested tables.&lt;br /&gt; &lt;/li&gt;   &lt;li&gt;&lt;a href="http://oraclesvca2.oracle.com/docs/cd/B14117_01/server.101/b10759/statements_2011.htm#sthref3243"&gt;Alter Sequence&lt;/a&gt;: Admit it ... you thought you were going to be able to change the current value with it, but then found you just had to drop the sequence and recreate it, so that's what you did.&lt;/li&gt;   &lt;li&gt;&lt;a href="http://oraclesvca2.oracle.com/docs/cd/B14117_01/server.101/b10759/statements_4006.htm#i2058947"&gt;Associate/Dissociate Statistics&lt;/a&gt;: What?&lt;/li&gt; &lt;/ul&gt; Well, I pride myself on the high education level of my readership, and also it's high regard for risk-taking. If you have actually used one of these features in a production system, and it has actually made it past the DBA/watchdog, then please reply under the heading "&lt;span style="font-style: italic;"&gt;I have an unusual affinity for Shiny New Things, and have successfully used the following features in a production system:&lt;/span&gt;"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112356226689004582?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112356226689004582/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112356226689004582' title='22 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112356226689004582'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112356226689004582'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/list-sql-features-youve-probably-never.html' title='A List: SQL Features You&apos;ve Probably Never Used In Production'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112352463406229149</id><published>2005-08-08T11:57:00.000-06:00</published><updated>2005-08-08T12:10:34.076-06:00</updated><title type='text'>A List: Accessing Part Of A Table Quickly</title><content type='html'>I like lists. In particular, I like to make little lists of Oracle features that have some commonality in the way they work, or in what they do.&lt;br /&gt;&lt;br /&gt;Today's list is &lt;span style="font-style: italic;"&gt;Oracle Features For Accessing Part Of A Table Quickly&lt;/span&gt;. Quicker than scanning the whole table anyway, and assuming that the table is not of trivial size. Here's what I have so far:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96524/c11schem.htm#3239"&gt;Creating an Index&lt;/a&gt;: obviously.&lt;/li&gt;   &lt;li&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96524/c11schem.htm#23878"&gt;Making the Table Index-Organized&lt;/a&gt;: Is that too similar to Option 1 to justify a new heading, do you think?&lt;/li&gt;   &lt;li&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96524/c11schem.htm#25479"&gt;Placing The Table In A Cluster&lt;/a&gt;: Hash or indexed.&lt;/li&gt;   &lt;li&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96524/c11schem.htm#31305"&gt;Partitioning The Table&lt;/a&gt;: Partition pruning being the key feature here, or through using the PARTITION or SUBPARTITION clauses of the query table expression.&lt;/li&gt;   &lt;li&gt;&lt;a href="http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96524/c11schem.htm#18094"&gt;Creating a Materialized View&lt;/a&gt;: By precomputing the result set for a query that requires only part of the full table. Query rewrite optional, I suppose.&lt;/li&gt; &lt;/ol&gt; Off the top of my head, that's all I can think of right now. Other suggestions welcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112352463406229149?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112352463406229149/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112352463406229149' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112352463406229149'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112352463406229149'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/list-accessing-part-of-table-quickly.html' title='A List: Accessing Part Of A Table Quickly'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112351626991200820</id><published>2005-08-08T09:38:00.000-06:00</published><updated>2005-08-08T09:51:10.336-06:00</updated><title type='text'>Trouble Down Under</title><content type='html'>I see that DKB and HJR are having at it again.&lt;br /&gt;&lt;br /&gt;DKB posted some inflammatory comments &lt;a href="http://dba-oracle.blogspot.com/2005/08/death-of-offshoring.html"&gt;here&lt;/a&gt;, and HJR posted responses &lt;a href="http://www.dizwell.com/2005/08/that-old-humbug-magic.html"&gt;here&lt;/a&gt;, &lt;a href="http://www.dizwell.com/2005/08/gosh-whod-have-thunk-it.html"&gt;here&lt;/a&gt;, and &lt;a href="http://www.dizwell.com/2005/08/bullys-wife-speaks.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So apparantly DKB's secret location from which he is broadcasting is &lt;a href="http://mikerault.blogspot.com/2005/08/hard-at-work-in-paradise.html"&gt;Australia&lt;/a&gt;. I'm sure he knows his own business, but it seems to me that his blog entry is very derogatory towards the people paying the bill for his consultancy ... "&lt;span style="font-style: italic;"&gt;Offshoring (the use of grossly under-trained and unskilled IT professionals)&lt;/span&gt;" ... "&lt;span style="font-style: italic;"&gt;if you are an IT manager stupid enough to entrust a mission-critical computer system to a foreign “offshore” developer firm&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;I think that it's nice that Burleson Consulting now has a legal presence in Australia .. DKB and HJR can get on with their legal business without bothering the rest of us. On a side note, while OraBlogs is &lt;a href="http://www.dizwell.com/2005/08/bullys-wife-speaks.html"&gt;getting notices&lt;/a&gt; that they are rendering copyrighted images, Don's own forum makes extensive use of copyrighted images. Like I say though, doubtless he knows his own business ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112351626991200820?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112351626991200820/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112351626991200820' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112351626991200820'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112351626991200820'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/trouble-down-under.html' title='Trouble Down Under'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11995638.post-112205161570896594</id><published>2005-08-08T07:00:00.000-06:00</published><updated>2005-08-08T07:43:05.196-06:00</updated><title type='text'>Daylight Savings Time</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Update&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Looks like the journos have figured out the downside ... http://www.cnn.com/2005/TECH/08/08/daylight.saving.ap/index.html&lt;br /&gt;&lt;br /&gt;The good news though: "&lt;span style="font-style: italic;"&gt;Missiles won't be launching&lt;/span&gt;". I don't know how they expect the unscrupulous to make a profit out of something if reputable news media aren't going to scream hysterically about it for months in advance, in the style of The Great Y2K Fiasco. Ah, how fondly I recall the sweet satisfaction of waking up on January 1st 2000, having taken not a single precaution against the promised apocalypse, and finding everything working completely normally.&lt;br /&gt;&lt;br /&gt;Anyway, this is a serious business in its own way: I recall being asked a few years ago to opine on a bid for a state system that was being converted to Oracle. The system defined funding for various state entities, and virtually the entire business logic was in effect defined by the state legislature. As such the funding model was vulnerable to change at any time, even retrospectively, and the only limit to the scope of change was the imagination of the state representatives and their advisors. For a fixed price contract and with existing staff already reeling from a series of recent changes it would have been a risk management nightmare. "Thumbs down" for that one.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Original Article&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Heads-up people!&lt;br /&gt;&lt;br /&gt;CNN are &lt;a href="http://www.cnn.com/2005/POLITICS/07/22/congress.daylighttime.ap/index.html"&gt;reporting&lt;/a&gt; on imminent changes to daylight savings time.&lt;br /&gt;&lt;br /&gt;"&lt;span style="font-style: italic;"&gt;House and Senate negotiators on an energy bill agreed to begin daylight-saving time three weeks earlier, on the second Sunday in March, and extend it by one week to the first Sunday in November.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Lawmakers said they hoped to complete the energy legislation next week&lt;/span&gt;."&lt;br /&gt;&lt;br /&gt;I wonder how much bespoke code this is going to affect? I'm supposing that there will be some Oracle patches to deal with the required changes to TIMESTAMP WITH TIMEZONE, etc.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://otn.oracle.com/pls/db10g/db10g.drilldown?remark=quick_search&amp;amp;word=daylight+savings+time"&gt;Here's&lt;/a&gt; a search on the 10g documentation for "daylight savings time", by the way.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11995638-112205161570896594?l=oraclesponge.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oraclesponge.blogspot.com/feeds/112205161570896594/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11995638&amp;postID=112205161570896594' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112205161570896594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11995638/posts/default/112205161570896594'/><link rel='alternate' type='text/html' href='http://oraclesponge.blogspot.com/2005/08/daylight-savings-time.html' title='Daylight Savings Time'/><author><name>David Aldridge</name><uri>http://www.blogger.com/profile/12440658753245953038</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry></feed>
