<?xml version="1.0" encoding="utf-8"?>
<presentation width="720" height="540" start="play" buildNum="5.1.246.246">
	<presentationTitle>Optimising through Understanding</presentationTitle>
	<speakers>
		<speaker>
			<name>Presented By:</name>
			<speakerTitle>Oracle University</speakerTitle>
		</speaker>
	</speakers>
	<backgrounds>
		<background url="Master80000000.swf"/>
	</backgrounds>
	<search url="srchdata.xml"/>
	<slides>
		<slide id="381" frameRate="30" totalFrames="235" advance="auto" type="normal">
			<content url="Slide1.swf"/>
			<slideBackground index="0" frameToPlay="1" duration="2" showAfterFrame="0"/>
			<slideTitle>Optimising through Understanding </slideTitle>
			<notes isHTML="false">   Push_subq.sql and (especially) no_push_subq.sql  Some subqueries in 9i will not unnest, but will push.  C_ordered for tables Cost permutations.sql  Gets unnest in 10g, semijoin, right semi  We are going to examine variations of a single query, involving a couple of subqueries, to help us understand the what Oracle can do with a query, what it can’t do, and how we can determine what we want it to do.  </notes>
			<slideThumbnail url="thumb.swf" frame="1"/>
			<slideSpeaker index="0"/>
			<audio url="a24x1.mp3"/>
		</slide>
		<slide id="380" frameRate="30" totalFrames="1504" advance="auto" type="normal">
			<content url="Slide2.swf"/>
			<slideBackground index="0" frameToPlay="3" duration="2" showAfterFrame="0"/>
			<slideTitle>Who am I ? </slideTitle>
			<notes isHTML="false">   Before we begin, I’ll just give you a brief introduction to who I am.  </notes>
			<slideThumbnail url="thumb.swf" frame="2"/>
			<slideSpeaker index="0"/>
			<audio url="a24x2.mp3"/>
		</slide>
		<slide id="391" frameRate="30" totalFrames="2565" advance="auto" type="normal">
			<content url="Slide3.swf"/>
			<slideBackground index="0" frameToPlay="5" duration="2" showAfterFrame="0"/>
			<slideTitle>Highlights </slideTitle>
			<notes isHTML="false">   Over the course of the next hour, we are going to start with the basic framework of a complex query, and gradually take it apart looking at different optimizer options in isolation. Once we’ve done that, we can put the query back together and examine the optimizer’s basic strategy, and what this means in terms of what is and is not possible. Finally we note that the “best” execution path may be one that we choose because we have a solid understanding of the data. We may even decide on an execution path that the optimizer is literally unable to produce unaided.  </notes>
			<slideThumbnail url="thumb.swf" frame="3"/>
			<slideSpeaker index="0"/>
			<audio url="a24x3.mp3"/>
		</slide>
		<slide id="372" frameRate="30" totalFrames="1889" advance="auto" type="normal">
			<content url="Slide4.swf"/>
			<slideBackground index="0" frameToPlay="7" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="1068" end="1083"/>
			</clickAnimations>
			<slideTitle>Template SQL: </slideTitle>
			<notes isHTML="false">   So this is the basic structure of our query. We have a simple join between two tables, with some simple filter conditions on both tables, and two subqueries, one operating against each table. In it’s most general form, the predicates could be combined with a mixture of Ands and ORs; the subqueries could be INs, EXISTS, or their negation; or could simple be atithmetic comparisons on correlated, or non-correlated subqueries. </notes>
			<slideThumbnail url="thumb.swf" frame="4"/>
			<slideSpeaker index="0"/>
			<audio url="a24x4.mp3"/>
		</slide>
		<slide id="382" frameRate="30" totalFrames="2015" advance="auto" type="normal">
			<content url="Slide5.swf"/>
			<slideBackground index="0" frameToPlay="9" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="1658" end="1673"/>
			</clickAnimations>
			<slideTitle>Example </slideTitle>
			<notes isHTML="false">   Here, to make the general structure more concrete, is an example with a couple of simple correlated existence tests. We could imagine all sorts of ways in which the optimizer (or we) might choose to operate this query to get the result set with the minimum amount of work. Before we look at the whole thing, though, let’s take parts of it in isolation.  </notes>
			<slideThumbnail url="thumb.swf" frame="5"/>
			<slideSpeaker index="0"/>
			<audio url="a24x5.mp3"/>
		</slide>
		<slide id="400" frameRate="30" totalFrames="5313" advance="auto" type="normal">
			<content url="Slide6.swf"/>
			<slideBackground index="0" frameToPlay="11" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="4867" end="4882"/>
			</clickAnimations>
			<slideTitle>Use of qb_name() </slideTitle>
			<notes isHTML="false">   We’ll start with a 10g feature – the qb_name() hint. Every single query block (roughly speaking every subquery) in a SQL statement can be given a name with the qb_name() hint. Once a query block has been named, we can make references to object in that query block from higher levels of the statement in the hints that we write. Every hint (probably) can have a new ‘first parameter’ which is the name of the query block to which it applies. The name has to be preceded with the @ sign. Tables can then be qualified with the query block name (again with the @ sign) . In this example, you’ll also notice the enhanced version of the leading() hint in 10g – you can specify every table in the query in the right order, and if there is a legal way to get to that order, Oracle will use it as the single join order it examines to optimize the query. We haven’t included t4 in the leading() hint because it is set to “not unnest” and. So it is going to run as a late subquery.  </notes>
			<slideThumbnail url="thumb.swf" frame="6"/>
			<slideSpeaker index="0"/>
			<audio url="a24x6.mp3"/>
		</slide>
		<slide id="399" frameRate="30" totalFrames="5135" advance="auto" type="normal">
			<content url="Slide7.swf"/>
			<slideBackground index="0" frameToPlay="13" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="2185" end="2200"/>
				<clickAnimation start="4953" end="4968"/>
			</clickAnimations>
			<slideTitle>Effect of @qb_name </slideTitle>
			<notes isHTML="false">   Here’s the execution plan for our original query with the leading() hint from the previous slide included.  leading(t1@main, t3@main, t2@subq2) Note that the order is t1, t3, then t2 with a semi-join, and t4 (no_unnest) as a filter.  One of the options for dbms_xplan.display() allows use to see table aliases and query block names – so we can see that we have a transformed block of three tables, plus one block which has not been transformed. (Could we use no_query_transformation(@subq4) ? YES !!    </notes>
			<slideThumbnail url="thumb.swf" frame="7"/>
			<slideSpeaker index="0"/>
			<audio url="a24x7.mp3"/>
		</slide>
		<slide id="383" frameRate="30" totalFrames="3248" advance="auto" type="normal">
			<content url="Slide8.swf"/>
			<slideBackground index="0" frameToPlay="15" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="1666" end="1681"/>
				<clickAnimation start="2496" end="2511"/>
			</clickAnimations>
			<slideTitle>Semi-join: </slideTitle>
			<notes isHTML="false">   Let’s go back to the transformations available for a single subquery). In this case we could have a small volume of data in t1 that can be accessed very efficiently by an index on n2; and an efficient access path to find the corresponding rows in t2. So Oracle converts the query into a nested loop join – stopping at the first success at t2 for every row it hits on t1. </notes>
			<slideThumbnail url="thumb.swf" frame="8"/>
			<slideSpeaker index="0"/>
			<audio url="a24x8.mp3"/>
		</slide>
		<slide id="384" frameRate="30" totalFrames="2897" advance="auto" type="normal">
			<content url="Slide9.swf"/>
			<slideBackground index="0" frameToPlay="17" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="1710" end="1725"/>
				<clickAnimation start="2622" end="2637"/>
			</clickAnimations>
			<slideTitle>Unnesting: </slideTitle>
			<notes isHTML="false">    But if there is no efficient access path into t2, the plan has to change. It could become a hash semi-join into t2.  However, we have an independent predicate on t2 that returns a few rows very efficiently, and we have an efficient way of getting into t1 based on the value of n1.  So the optimizer can generate a unique set of values from t2, then use those as the outer table in a nested loop join into t1. </notes>
			<slideThumbnail url="thumb.swf" frame="9"/>
			<slideSpeaker index="0"/>
			<audio url="a24x9.mp3"/>
		</slide>
		<slide id="385" frameRate="30" totalFrames="5349" advance="auto" type="normal">
			<content url="Slide10.swf"/>
			<slideBackground index="0" frameToPlay="19" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="2784" end="2799"/>
				<clickAnimation start="5106" end="5121"/>
			</clickAnimations>
			<slideTitle>Access  subquery: </slideTitle>
			<notes isHTML="false">   In this case (which uses a completely different table structure) we have a unique index on (id_parent, id_child), and we are doing a classic: “most recent of” query. The subquery is executed first, and the single result is used as an access predicate to allow Oracle a unique access into a unique index.  </notes>
			<slideThumbnail url="thumb.swf" frame="10"/>
			<slideSpeaker index="0"/>
			<audio url="a24x10.mp3"/>
		</slide>
		<slide id="422" frameRate="30" totalFrames="3934" advance="auto" type="normal">
			<content url="Slide11.swf"/>
			<slideBackground index="0" frameToPlay="21" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="2475" end="2490"/>
				<clickAnimation start="3482" end="3497"/>
			</clickAnimations>
			<slideTitle>Filter subquery: </slideTitle>
			<notes isHTML="false">   In this case, because of the OR clause, the optimizer cannot unnest the subquery – it has to pick up all the rows where n2 between 100 and 200, but also has to examine every other row in the table to check the subquery. In principle, Oracle will run the subquery once for EVERY single row in the table (except the ones that have already passed the n2 test).  </notes>
			<slideThumbnail url="thumb.swf" frame="11"/>
			<slideSpeaker index="0"/>
			<audio url="a24x11.mp3"/>
		</slide>
		<slide id="386" frameRate="30" totalFrames="5760" advance="auto" type="normal">
			<content url="Slide12.swf"/>
			<slideBackground index="0" frameToPlay="23" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="720" end="735"/>
				<clickAnimation start="1768" end="1783"/>
				<clickAnimation start="5298" end="5313"/>
			</clickAnimations>
			<slideTitle>Subquery with OR: </slideTitle>
			<notes isHTML="false">   Sometimes you just write the unnest manually.  In this case we use OR expansion (not yet implemented) to get two non-colliding results.  Watch out for NULL effects. </notes>
			<slideThumbnail url="thumb.swf" frame="12"/>
			<slideSpeaker index="0"/>
			<audio url="a24x12.mp3"/>
		</slide>
		<slide id="387" frameRate="30" totalFrames="5885" advance="auto" type="normal">
			<content url="Slide13.swf"/>
			<slideBackground index="0" frameToPlay="25" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="5886" end="5901"/>
			</clickAnimations>
			<slideTitle>(Scalar) Subquery caching: </slideTitle>
			<notes isHTML="false">   There is some aid from the problem of running a filter subquery for every row in the table. A feature (from 8.0) known as scalar subquery caching. In general it is quite good to go for unnesting, because filter subqueries are unpredictable due to the hash algorithm used for caching.   How many times could this run ? Min 6, max 20,000. Response time 0.01 -&gt; 150 seconds CPU. A small change in the actual data (a rogue value appearing) could make a massive difference in the number of times the query runs. In 8i and 9i you get 256 values in the hash table. In 10g you get seem to get 1024 for numbers, but the table size is limited to 64KB in 10g, which means problems for unconstrained text values which deemed to be 4,000 bytes each.    </notes>
			<slideThumbnail url="thumb.swf" frame="13"/>
			<slideSpeaker index="0"/>
			<audio url="a24x13.mp3"/>
		</slide>
		<slide id="426" frameRate="30" totalFrames="230" advance="pause" type="normal">
			<content url="Slide14.swf"/>
			<slideBackground index="0" frameToPlay="27" duration="2" showAfterFrame="0"/>
			<embeddedContents>
				<embeddedContent url="./resources/embedded_flash_1.swf" container="mediaContainer.flash1.content" duration="0" playAfterTime="0"/>
			</embeddedContents>
			<slideTitle>Demo </slideTitle>
			<notes isHTML="false">
			</notes>
			<slideThumbnail url="thumb.swf" frame="14"/>
			<slideSpeaker index="0"/>
			<audio url="a24x14.mp3"/>
		</slide>
		<slide id="427" frameRate="30" totalFrames="587" advance="auto" type="normal">
			<content url="Slide15.swf"/>
			<slideBackground index="0" frameToPlay="29" duration="2" showAfterFrame="0"/>
			<slideTitle>(Scalar) Subquery caching: </slideTitle>
			<notes isHTML="false">   There is some aid from the problem of running a filter subquery for every row in the table. A feature (from 8.0) known as scalar subquery caching. In general it is quite good to go for unnesting, because filter subqueries are unpredictable due to the hash algorithm used for caching.   How many times could this run ? Min 6, max 20,000. Response time 0.01 -&gt; 150 seconds CPU. A small change in the actual data (a rogue value appearing) could make a massive difference in the number of times the query runs. In 8i and 9i you get 256 values in the hash table. In 10g you get seem to get 1024 for numbers, but the table size is limited to 64KB in 10g, which means problems for unconstrained text values which deemed to be 4,000 bytes each.    </notes>
			<slideThumbnail url="thumb.swf" frame="15"/>
			<slideSpeaker index="0"/>
			<audio url="a24x15.mp3"/>
		</slide>
		<slide id="393" frameRate="30" totalFrames="5266" advance="auto" type="normal">
			<content url="Slide16.swf"/>
			<slideBackground index="0" frameToPlay="31" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="4136" end="4151"/>
				<clickAnimation start="5029" end="5044"/>
			</clickAnimations>
			<slideTitle>Scalar Subquery solution ? </slideTitle>
			<notes isHTML="false">   If you cannot unnest, and if you have wild fluctuations in performance because of hash collisions, you could ensure the values supplied to the subquery appear in order – then oracle run-time simply remembers the return values from “the previous” row. But this is a little dangerous – you should not depend on internal mechanisms.   </notes>
			<slideThumbnail url="thumb.swf" frame="16"/>
			<slideSpeaker index="0"/>
			<audio url="a24x16.mp3"/>
		</slide>
		<slide id="405" frameRate="30" totalFrames="1595" advance="auto" type="normal">
			<content url="Slide17.swf"/>
			<slideBackground index="0" frameToPlay="33" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="1004" end="1019"/>
				<clickAnimation start="1244" end="1259"/>
			</clickAnimations>
			<slideTitle>Filter Postponement (1) </slideTitle>
			<notes isHTML="false">   Another feature to be aware of with filter subqueries is there effect on the arithmetic, and how this is incompatible with their impact at runtime. We have a query here where I can include or exclude the subquery. The query joins t1 and t3, but the subquery is against t1. Check the plans and the cardinality. </notes>
			<slideThumbnail url="thumb.swf" frame="17"/>
			<slideSpeaker index="0"/>
			<audio url="a24x17.mp3"/>
		</slide>
		<slide id="394" frameRate="30" totalFrames="3463" advance="auto" type="normal">
			<content url="Slide18.swf"/>
			<slideBackground index="0" frameToPlay="35" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="517" end="532"/>
				<clickAnimation start="3070" end="3085"/>
			</clickAnimations>
			<slideTitle>Filter Postponement (2) </slideTitle>
			<notes isHTML="false">   Without the subquery, the cardinality of t1 is 157, and the join cardinality it 173. With the subquery, the cardinality of t1 drops to 5% of 157 – which reduces the join cardinality to 9. But the subquery does not run until AFTER the join has been operated. So the number of calls to the subquery is 20 times larger than the number costed for. This type of change could result in an indexed nested loop instead of a hash join – have two subqueries against t1 and it becomes very likely, as you get the selectivity down to 5% of 5%.  </notes>
			<slideThumbnail url="thumb.swf" frame="18"/>
			<slideSpeaker index="0"/>
			<audio url="a24x18.mp3"/>
		</slide>
		<slide id="408" frameRate="30" totalFrames="2211" advance="auto" type="normal">
			<content url="Slide19.swf"/>
			<slideBackground index="0" frameToPlay="37" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="1816" end="1831"/>
				<clickAnimation start="1948" end="1963"/>
			</clickAnimations>
			<slideTitle>Filter Postponement (3) </slideTitle>
			<notes isHTML="false">   10g behaves much better than 9i in this timing/costing split. But you can improve 9i (and earlier) by using the push_subq hint – which changes its use in 10g: current 9i use of this hint WILL NOT WORK on the next upgrade.  </notes>
			<slideThumbnail url="thumb.swf" frame="19"/>
			<slideSpeaker index="0"/>
			<audio url="a24x19.mp3"/>
		</slide>
		<slide id="409" frameRate="30" totalFrames="2738" advance="auto" type="normal">
			<content url="Slide20.swf"/>
			<slideBackground index="0" frameToPlay="39" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="626" end="641"/>
				<clickAnimation start="1580" end="1595"/>
			</clickAnimations>
			<slideTitle>Filter Postponement (4) </slideTitle>
			<notes isHTML="false">   Without pushing, the 10g plan shows a late running subquery – but the t1 cardinality and join cardinality have not suffered the 5% factor. When the subquery is pushed, the 5% appears in the right place. Note – however – that the FILTER operation has gone missing. It has been squashed into the tablescan of t1 – which really ought to be the filter line, and the scan of t1 should be one line down and one step to the right.  </notes>
			<slideThumbnail url="thumb.swf" frame="20"/>
			<slideSpeaker index="0"/>
			<audio url="a24x20.mp3"/>
		</slide>
		<slide id="388" frameRate="30" totalFrames="641" advance="auto" type="normal">
			<content url="Slide21.swf"/>
			<slideBackground index="0" frameToPlay="41" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="419" end="434"/>
				<clickAnimation start="531" end="546"/>
			</clickAnimations>
			<slideTitle>Filter Subquery join effects </slideTitle>
			<notes isHTML="false">   Another aspect of filter subqueries if we do not push them is that the number of times the subquery runs can be affected by the join method that takes place before the subquery. We can see operation counts by enabling rowsource execution statistics. This can be expensive on CPU usage, and should be done rarely. It populates the view v$sql_plan_statistics – and there is a hint in 10g to make this easy.  </notes>
			<slideThumbnail url="thumb.swf" frame="21"/>
			<slideSpeaker index="0"/>
			<audio url="a24x21.mp3"/>
		</slide>
		<slide id="407" frameRate="30" totalFrames="1526" advance="auto" type="normal">
			<content url="Slide22.swf"/>
			<slideBackground index="0" frameToPlay="43" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="483" end="498"/>
				<clickAnimation start="919" end="934"/>
				<clickAnimation start="1047" end="1062"/>
				<clickAnimation start="1166" end="1181"/>
			</clickAnimations>
			<slideTitle>Filter Subquery join effects </slideTitle>
			<notes isHTML="false">   Querying dbms_xplan.display_cursor(null,null,’ALLSTATS LAST’) we can see the statistics for the last run of the most recent statement we executed. (You need to have serveroutput off for this to work, or the last statement will be the call to dbms_output.get_lines).  With the nested loop join, the data order of the driving column for the subquery s dictated by the first table – and this maximises the benefit of scalar subquery caching. With the hash join, the data order of the driving column for the subquery is dictated by the second table. And this can mean we run the subquery more times.   </notes>
			<slideThumbnail url="thumb.swf" frame="22"/>
			<slideSpeaker index="0"/>
			<audio url="a24x22.mp3"/>
		</slide>
		<slide id="395" frameRate="30" totalFrames="1999" advance="auto" type="normal">
			<content url="Slide23.swf"/>
			<slideBackground index="0" frameToPlay="45" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="602" end="617"/>
				<clickAnimation start="1627" end="1642"/>
			</clickAnimations>
			<slideTitle>Join Orders (1) </slideTitle>
			<notes isHTML="false">   It’s not just run-time that can be affected. It’s worth checking how hard the optimizer has to work when handling a statement with subqueries. It changes with version of Oracle. A simple check in the 10053 trace file (CBO trace) is to look for the number of lines where Oracle reports a ‘Join Order’ to see how many get examined. Consider this query where we want the employees that earn more than the average salary for their department. 9i and 10g produced the same plan (unnest, inline view and hash join) for this query – although 10g did a hash group by – but how did they get to that decision. </notes>
			<slideThumbnail url="thumb.swf" frame="23"/>
			<slideSpeaker index="0"/>
			<audio url="a24x23.mp3"/>
		</slide>
		<slide id="397" frameRate="30" totalFrames="4361" advance="auto" type="normal">
			<content url="Slide24.swf"/>
			<slideBackground index="0" frameToPlay="47" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="1374" end="1389"/>
				<clickAnimation start="2189" end="2204"/>
				<clickAnimation start="3949" end="3964"/>
			</clickAnimations>
			<slideTitle>Join Orders (2) </slideTitle>
			<notes isHTML="false">   The plans  In Oracle 9, there are two stages only: Work out the strategy of the inline view Work out the cost of joining the view to the base table  In 10g we then work out the cost of doing complex view merging between the view and the base table. Then we work out half a dozen other options. The optimization CPU, memory, and latch activity goes up significantly.  </notes>
			<slideThumbnail url="thumb.swf" frame="24"/>
			<slideSpeaker index="0"/>
			<audio url="a24x24.mp3"/>
		</slide>
		<slide id="401" frameRate="30" totalFrames="1983" advance="auto" type="normal">
			<content url="Slide25.swf"/>
			<slideBackground index="0" frameToPlay="49" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="483" end="513"/>
				<clickAnimation start="1206" end="1221"/>
			</clickAnimations>
			<slideTitle>Join Orders (3) </slideTitle>
			<notes isHTML="false">   This might look like a threat in the case of our sample query – how many different things will the optimizer try to work out ? In fact, because we have simple existence subqueries with non-null columns and primary keys all over the place, we find that Oracle has invoked ‘non-costed’ transformation to turn the query into a straight four-table join. This means it only looks at one general plan – with 24 (4 * 3 * 2 * 1) join orders. This “non-costed” approach is not necessarily the right thing to do with multiple subqueries (in my opinion), and there are execution plans which simply cannot be created from a 4-table join. </notes>
			<slideThumbnail url="thumb.swf" frame="25"/>
			<slideSpeaker index="0"/>
			<audio url="a24x25.mp3"/>
		</slide>
		<slide id="398" frameRate="30" totalFrames="1595" advance="auto" type="normal">
			<content url="Slide26.swf"/>
			<slideBackground index="0" frameToPlay="51" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="1416" end="1431"/>
			</clickAnimations>
			<slideTitle>Join Orders (4) </slideTitle>
			<notes isHTML="false">   These are the join orders examined – you will note that a few are skipped. This is because the initial stages of a previous join are the same, and the previous join order was aborted early as being more expensive than the current best option. </notes>
			<slideThumbnail url="thumb.swf" frame="26"/>
			<slideSpeaker index="0"/>
			<audio url="a24x26.mp3"/>
		</slide>
		<slide id="403" frameRate="30" totalFrames="1325" advance="auto" type="normal">
			<content url="Slide27.swf"/>
			<slideBackground index="0" frameToPlay="53" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="480" end="495"/>
				<clickAnimation start="1228" end="1243"/>
			</clickAnimations>
			<slideTitle>Forcing Join orders (1) </slideTitle>
			<notes isHTML="false">   Despite some orders being skipped, we can force Oracle to evaluate and use the paths (or at least display them). This only works for very simple cases. What happens if you have multiple complex query blocks – you only get on choice of permutation number. </notes>
			<slideThumbnail url="thumb.swf" frame="27"/>
			<slideSpeaker index="0"/>
			<audio url="a24x27.mp3"/>
		</slide>
		<slide id="423" frameRate="30" totalFrames="2082" advance="auto" type="normal">
			<content url="Slide28.swf"/>
			<slideBackground index="0" frameToPlay="55" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="109" end="124"/>
			</clickAnimations>
			<slideTitle>Forcing Join orders (2) </slideTitle>
			<notes isHTML="false">   It is worth noting that the execution plans can appear to contradict the join orders. This is a common reason why people sometimes think that Oracle has ignored a hint. With HASH joins specifically, when you ‘join the next table’ – Oracle can choose whether that new table should be the build (hash) table or the probe (second) table. There is a hint swap_join_inputs() in 9i which forces it to be the build table; and a 10g hint no_swap_join_inputs() that forces it to be the probe table. </notes>
			<slideThumbnail url="thumb.swf" frame="28"/>
			<slideSpeaker index="0"/>
			<audio url="a24x28.mp3"/>
		</slide>
		<slide id="424" frameRate="30" totalFrames="3403" advance="auto" type="normal">
			<content url="Slide29.swf"/>
			<slideBackground index="0" frameToPlay="57" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="1477" end="1492"/>
			</clickAnimations>
			<slideTitle>Forcing Join orders (3) </slideTitle>
			<notes isHTML="false">   It is also interesting to note that, although there are three (four) different strategies that Oracle could choose to transform a subquery, sometimes the options are constrained by the previous actions in the join order. In this case we see t4 used as an in-line view (because that’s the only way you can join t1 and t4 through the necessary cartesian merge join), and t3 being access through a semi-join. Being 10g, the semi-join has been set as a hash semi-join, which can then be reversed (to become an outer join the wrong way around). Every version brings new little details.  </notes>
			<slideThumbnail url="thumb.swf" frame="29"/>
			<slideSpeaker index="0"/>
			<audio url="a24x29.mp3"/>
		</slide>
		<slide id="406" frameRate="30" totalFrames="1719" advance="auto" type="normal">
			<content url="Slide30.swf"/>
			<slideBackground index="0" frameToPlay="59" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="1238" end="1253"/>
			</clickAnimations>
			<slideTitle>The meaning of the query (1) </slideTitle>
			<notes isHTML="false">   The best way to work out the most efficient operation is to know the data. Looking at t1,  could join to t3  could filter against t2  </notes>
			<slideThumbnail url="thumb.swf" frame="30"/>
			<slideSpeaker index="0"/>
			<audio url="a24x30.mp3"/>
		</slide>
		<slide id="412" frameRate="30" totalFrames="2438" advance="auto" type="normal">
			<content url="Slide31.swf"/>
			<slideBackground index="0" frameToPlay="61" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="1716" end="1731"/>
				<clickAnimation start="2249" end="2264"/>
			</clickAnimations>
			<slideTitle>What if … (1) </slideTitle>
			<notes isHTML="false">   If we decide that the subquery against t2 eliminates more data than the join to t3, then we could force the subquery to run before the join.  </notes>
			<slideThumbnail url="thumb.swf" frame="31"/>
			<slideSpeaker index="0"/>
			<audio url="a24x31.mp3"/>
		</slide>
		<slide id="413" frameRate="30" totalFrames="2018" advance="auto" type="normal">
			<content url="Slide32.swf"/>
			<slideBackground index="0" frameToPlay="63" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="1296" end="1311"/>
				<clickAnimation start="1789" end="1804"/>
			</clickAnimations>
			<slideTitle>What if … (2) </slideTitle>
			<notes isHTML="false">   But, the subquery may be fairly expensive on disk or CPU, to so we might want to minise the number of times it runs. Conversely, the nature of the join to t3 (hence the cost of the join) may be unchanged by the fact that we have filtered data out already – so there may be no benefit in running the subquery early. So we could choose to join then filter. In this case, by filtering early, we changed the join to t3 from a hash join (expensive) to a nested loop (possibly cheaper – if it is a precise nested loop). </notes>
			<slideThumbnail url="thumb.swf" frame="32"/>
			<slideSpeaker index="0"/>
			<audio url="a24x32.mp3"/>
		</slide>
		<slide id="416" frameRate="30" totalFrames="923" advance="auto" type="normal">
			<content url="Slide33.swf"/>
			<slideBackground index="0" frameToPlay="65" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="712" end="727"/>
			</clickAnimations>
			<slideTitle>The meaning of the query (2) </slideTitle>
			<notes isHTML="false">   But notice that both subqueries have their own filter-only predicates. How much data would we get from each subquery, and how efficiently, if we started with one of these subquery tables. </notes>
			<slideThumbnail url="thumb.swf" frame="33"/>
			<slideSpeaker index="0"/>
			<audio url="a24x33.mp3"/>
		</slide>
		<slide id="414" frameRate="30" totalFrames="1164" advance="auto" type="normal">
			<content url="Slide34.swf"/>
			<slideBackground index="0" frameToPlay="67" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="485" end="500"/>
				<clickAnimation start="816" end="831"/>
			</clickAnimations>
			<slideTitle>What if … (3) </slideTitle>
			<notes isHTML="false">   If we can’t get from t1 to t2 efficiently, maybe we can pick a small amount ofdata from t2 and then use an efficient access path into t1. In this case we then hash join to t3 </notes>
			<slideThumbnail url="thumb.swf" frame="34"/>
			<slideSpeaker index="0"/>
			<audio url="a24x34.mp3"/>
		</slide>
		<slide id="415" frameRate="30" totalFrames="3071" advance="auto" type="normal">
			<content url="Slide35.swf"/>
			<slideBackground index="0" frameToPlay="69" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="1328" end="1343"/>
				<clickAnimation start="1806" end="1821"/>
			</clickAnimations>
			<slideTitle>What if … (4) </slideTitle>
			<notes isHTML="false">   But a hash join to t3 might be very expensive What if join from t4 to t3 is as efficient at the join from t2 to t1. What if the number of rows from t4 and t2 are both small – a cartesian join of the selected data from t2 and t4 could be small and efficiently acquired, and a highly efficient path to t1 and t3 might then be very effecive. This is a path that few humans would think of – but it just falls out of the machines implacable processing of the join orders. It happens to be the default path for my query.  </notes>
			<slideThumbnail url="thumb.swf" frame="35"/>
			<slideSpeaker index="0"/>
			<audio url="a24x35.mp3"/>
		</slide>
		<slide id="417" frameRate="30" totalFrames="3051" advance="auto" type="normal">
			<content url="Slide36.swf"/>
			<slideBackground index="0" frameToPlay="71" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="2669" end="2684"/>
				<clickAnimation start="2778" end="2793"/>
				<clickAnimation start="2883" end="2898"/>
			</clickAnimations>
			<slideTitle>Impossible path </slideTitle>
			<notes isHTML="false">    But there are still cases where none of the 24 join orders work well.  </notes>
			<slideThumbnail url="thumb.swf" frame="36"/>
			<slideSpeaker index="0"/>
			<audio url="a24x36.mp3"/>
		</slide>
		<slide id="418" frameRate="30" totalFrames="1157" advance="auto" type="normal">
			<content url="Slide37.swf"/>
			<slideBackground index="0" frameToPlay="73" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="797" end="812"/>
			</clickAnimations>
			<slideTitle>Bushy Tree SQL </slideTitle>
			<notes isHTML="false">   We can make Oracle do something it doesn’t want to do. Create a couple of intermediate results and join them. For example – compare this summary of this week’s sales with the same week last year. Oracle will tend to join two big sets and aggregate when we can see that we want to aggregate two sets and join. The no_merge hint (or possibly subquery factoring with the /*+ materialize */ hint) can work for use here. Note that the materialize will cause global temporary tables to be dumped to the temp tablespace, whereas no_merge uses PGA memory.  </notes>
			<slideThumbnail url="thumb.swf" frame="37"/>
			<slideSpeaker index="0"/>
			<audio url="a24x37.mp3"/>
		</slide>
		<slide id="425" frameRate="30" totalFrames="1468" advance="auto" type="normal">
			<content url="Slide38.swf"/>
			<slideBackground index="0" frameToPlay="75" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="1077" end="1092"/>
			</clickAnimations>
			<slideTitle>Bushy Tree SQL (alt) </slideTitle>
			<notes isHTML="false">   We can make Oracle do something it doesn’t want to do. Create a couple of intermediate results and join them. For example – compare this summary of this week’s sales with the same week last year. Oracle will tend to join two big sets and aggregate when we can see that we want to aggregate two sets and join. The no_merge hint (or possibly subquery factoring with the /*+ materialize */ hint) can work for use here. Note that the materialize will cause global temporary tables to be dumped to the temp tablespace, whereas no_merge uses PGA memory.  </notes>
			<slideThumbnail url="thumb.swf" frame="38"/>
			<slideSpeaker index="0"/>
			<audio url="a24x38.mp3"/>
		</slide>
		<slide id="419" frameRate="30" totalFrames="769" advance="auto" type="normal">
			<content url="Slide39.swf"/>
			<slideBackground index="0" frameToPlay="77" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="545" end="560"/>
			</clickAnimations>
			<slideTitle>Bushy Tree plan </slideTitle>
			<notes isHTML="false">   This is the execution plan. VIEW means “in memory result set generated”. Then we hash join the two sets.  </notes>
			<slideThumbnail url="thumb.swf" frame="39"/>
			<slideSpeaker index="0"/>
			<audio url="a24x39.mp3"/>
		</slide>
		<slide id="420" frameRate="30" totalFrames="1001" advance="auto" type="normal">
			<content url="Slide40.swf"/>
			<slideBackground index="0" frameToPlay="79" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="633" end="648"/>
			</clickAnimations>
			<slideTitle>Bushy Tree picture </slideTitle>
			<notes isHTML="false">   The bushy tree picture.  </notes>
			<slideThumbnail url="thumb.swf" frame="40"/>
			<slideSpeaker index="0"/>
			<audio url="a24x40.mp3"/>
		</slide>
		<slide id="421" frameRate="30" totalFrames="4045" advance="auto" type="normal">
			<content url="Slide41.swf"/>
			<slideBackground index="0" frameToPlay="81" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="3552" end="3567"/>
			</clickAnimations>
			<slideTitle>Know your Data </slideTitle>
			<notes isHTML="false">   General principles Sketch out the picture of the data in E/R form to help, then walk from table to table.  </notes>
			<slideThumbnail url="thumb.swf" frame="41"/>
			<slideSpeaker index="0"/>
			<audio url="a24x41.mp3"/>
		</slide>
		<slide id="390" frameRate="30" totalFrames="1989" advance="auto" type="normal">
			<content url="Slide42.swf"/>
			<slideBackground index="0" frameToPlay="83" duration="2" showAfterFrame="0"/>
			<clickAnimations>
				<clickAnimation start="92" end="107"/>
				<clickAnimation start="283" end="298"/>
				<clickAnimation start="627" end="642"/>
			</clickAnimations>
			<slideTitle>Conclusion </slideTitle>
			<notes isHTML="false">   Know thy data.  </notes>
			<slideThumbnail url="thumb.swf" frame="42"/>
			<slideSpeaker index="0"/>
			<audio url="a24x42.mp3"/>
		</slide>
	</slides>
</presentation>
