Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005

rekharaghuram
from rekharaghuram More from this publisher
05.11.2015 Views

CHAPTER 10 ■ DATABASE TABLES 407 the setting of 1 would cause dynamic sampling to be used much less often. We can use an ALTER SESSION|SYSTEM command in Oracle9i Release 2 to make it behave the way Oracle 10g does by default, or we can use the dynamic sampling hint as follows: ops$tkyte@ORA9IR2> create global temporary table gtt 2 as 3 select * from scott.emp where 1=0; Table created. ops$tkyte@ORA9IR2> insert into gtt select * from scott.emp; 14 rows created. ops$tkyte@ORA9IR2> set autotrace traceonly explain ops$tkyte@ORA9IR2> select /*+ first_rows */ * from gtt; Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=HINT: FIRST_ROWS (Cost=17 Card=8168 Bytes... 1 0 TABLE ACCESS (FULL) OF 'GTT' (Cost=17 Card=8168 Bytes=710616) ops$tkyte@ORA9IR2> select /*+ first_rows dynamic_sampling(gtt 2) */ * from gtt; Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=HINT: FIRST_ROWS (Cost=17 Card=14 Bytes=1218) 1 0 TABLE ACCESS (FULL) OF 'GTT' (Cost=17 Card=14 Bytes=1218) ops$tkyte@ORA9IR2> set autotrace off Here, we set the dynamic sampling to level 2 for the table GTT in this query. Left to itself, the optimizer guessed 8,168 rows would be returned from the table GTT. Using dynamic sampling, the estimated cardinality will be much closer to reality (which leads to better query plans overall). Using the level 2 setting, the optimizer quickly scans the table to come up with more-realistic estimates of the true size of this table. In Oracle 10g, we should find this to be less of a problem, because the defaults will cause dynamic sampling to take place: ops$tkyte@ORA10G> create global temporary table gtt 2 as 3 select * from scott.emp where 1=0; Table created. ops$tkyte@ORA10G> insert into gtt select * from scott.emp; 14 rows created. ops$tkyte@ORA10G> set autotrace traceonly explain ops$tkyte@ORA10G> select * from gtt;

408 CHAPTER 10 ■ DATABASE TABLES Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=2 Card=14 Bytes=1218) 1 0 TABLE ACCESS (FULL) OF 'GTT' (TABLE (TEMP)) (Cost=2 Card=14 Bytes=1218) ops$tkyte@ORA10G> set autotrace off We get the right cardinality without having to ask for it. Dynamic sampling does not come free, however—there is a cost associated with having to perform it at query parse time. If we gathered appropriate representative statistics ahead of time, we could avoid this at hard parse time. That leads us in to DBMS_STATS. There are three methods to use DBMS_STATS to gather representative statistics. The first way is to use DBMS_STATS with the GATHER_SCHEMA_STATS or GATHER_DATABASE_STATS call. These procedures allow you to pass in a parameter, GATHER_TEMP, which is a Boolean and defaults to FALSE. When set to TRUE, any ON COMMIT PRESERVE ROWS global temporary table will have statistics gathered and stored (this technique will not work on ON COMMIT DELETE ROWS tables). Consider the following (note that this was done in an empty schema; the only objects are those you see created): ops$tkyte@ORA10G> create table emp as select * from scott.emp; Table created. ops$tkyte@ORA10G> create global temporary table gtt1 ( x number ) 2 on commit preserve rows; Table created. ops$tkyte@ORA10G> create global temporary table gtt2 ( x number ) 2 on commit delete rows; Table created. ops$tkyte@ORA10G> insert into gtt1 select user_id from all_users; 38 rows created. ops$tkyte@ORA10G> insert into gtt2 select user_id from all_users; 38 rows created. ops$tkyte@ORA10G> exec dbms_stats.gather_schema_stats( user ); PL/SQL procedure successfully completed. ops$tkyte@ORA10G> select table_name, last_analyzed, num_rows from user_tables; TABLE_NAME LAST_ANAL NUM_ROWS ------------------------------ --------- ---------- EMP 01-MAY-05 14 GTT1 GTT2

CHAPTER 10 ■ DATABASE TABLES 407<br />

the setting of 1 would cause dynamic sampling to be used much less often. We can use an<br />

ALTER SESSION|SYSTEM comm<strong>and</strong> in <strong>Oracle</strong>9i Release 2 to make it behave the way <strong>Oracle</strong> 10g<br />

does by default, or we can use the dynamic sampling hint as follows:<br />

ops$tkyte@ORA9IR2> create global temporary table gtt<br />

2 as<br />

3 select * from scott.emp where 1=0;<br />

Table created.<br />

ops$tkyte@ORA9IR2> insert into gtt select * from scott.emp;<br />

14 rows created.<br />

ops$tkyte@ORA9IR2> set autotrace traceonly explain<br />

ops$tkyte@ORA9IR2> select /*+ first_rows */ * from gtt;<br />

Execution Plan<br />

----------------------------------------------------------<br />

0 SELECT STATEMENT Optimizer=HINT: FIRST_ROWS (Cost=17 Card=8168 Bytes...<br />

1 0 TABLE ACCESS (FULL) OF 'GTT' (Cost=17 Card=8168 Bytes=710616)<br />

ops$tkyte@ORA9IR2> select /*+ first_rows dynamic_sampling(gtt 2) */ * from gtt;<br />

Execution Plan<br />

----------------------------------------------------------<br />

0 SELECT STATEMENT Optimizer=HINT: FIRST_ROWS (Cost=17 Card=14 Bytes=1218)<br />

1 0 TABLE ACCESS (FULL) OF 'GTT' (Cost=17 Card=14 Bytes=1218)<br />

ops$tkyte@ORA9IR2> set autotrace off<br />

Here, we set the dynamic sampling to level 2 for the table GTT in this query. Left to itself,<br />

the optimizer guessed 8,168 rows would be returned from the table GTT. Using dynamic sampling,<br />

the estimated cardinality will be much closer to reality (which leads to better query<br />

plans overall). Using the level 2 setting, the optimizer quickly scans the table to come up with<br />

more-realistic estimates of the true size of this table. In <strong>Oracle</strong> 10g, we should find this to be<br />

less of a problem, because the defaults will cause dynamic sampling to take place:<br />

ops$tkyte@ORA10G> create global temporary table gtt<br />

2 as<br />

3 select * from scott.emp where 1=0;<br />

Table created.<br />

ops$tkyte@ORA10G> insert into gtt select * from scott.emp;<br />

14 rows created.<br />

ops$tkyte@ORA10G> set autotrace traceonly explain<br />

ops$tkyte@ORA10G> select * from gtt;

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!