Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

2,065 views

Published on

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,065
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
189
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

  1. 1. Some SQL Techniques
  2. 2. Who am I •  Been with Oracle since 1993 •  User of Oracle since 1987 •  The “Tom” behind AskTom in Oracle Magazine www.oracle.com/oramag •  Expert Oracle Database Architecture •  Effective Oracle by Design •  Expert One on One Oracle •  Beginning Oracle
  3. 3. Agenda•  What do you need to write “good” SQL•  The Schema Matters•  Knowing what is available –  Using rownum (yes, to tune) –  Scalar subqueries –  Analytics –  Some hints•  Don’t tune queries!•  Other things –  Materialized Views –  With subquery factoring –  Merge –  …
  4. 4. What do you need to know…•  Access Paths –  There are a lot of them –  There is no best one (else there would be, well, one)•  A little bit of physics –  Full scans are not evil –  Indexes are not all goodness•  How the data is managed by Oracle –  high water marks for example –  IOT’s, clusters, etc•  What your query needs to actually do –  Is that outer join really necessary or “just in case”
  5. 5. Structures •  How the data is accessed and organized makes a difference –  ClusteringSelect *from orders o, line_items li ORDERS ORDERS & LINEwhere o.order# = li.order# LINE ITEMS ITEMSAnd o.order# = :order
  6. 6. Structures •  How the data is accessed and organized makes a difference –  Clustering –  Index Organized TablesSelect avg(price) STOCKS STOCKSFrom stocksWhere symbol = ‘ORCL’And stock_dt >= sysdate-5;
  7. 7. Structures •  How the data is accessed and organized makes a difference –  Clustering –  Index Organized Tables ORDERS ORDERS ORDERS –  Partitioning Europe USA Jan Jan Feb Feb Composite Partition Partition Large Table Higher and Manage Divide Performance Difficult to Conquer More flexibility to match Easier to Manage business needs Improve Performance
  8. 8. The Schema Matters•  A Lot!•  Tune this query: Select DOCUMENT_NAME, META_DATA from documents where userid=:x;•  That is about as easy as it gets (the SQL)•  Not too much we can do to rewrite it…•  But we’d like to make it better. Iot01.sql Cf.sql
  9. 9. Organization Countsops$tkyte%ORA11GR2> create table iot 2 ( username varchar2(30), 3 document_name varchar2(30), 4 other_data char(1000), 5 constraint iot_pk primary key (username,document_name)) 6 organization index 7 /Table created.ops$tkyte%ORA11GR2> create table heap 2 ( username varchar2(30), 3 document_name varchar2(30), 4 other_data char(1000), 5 constraint heap_pk primary key (username,document_name)) 6 /Table created.
  10. 10. Organization Countsops$tkyte%ORA11GR2> begin 2 for i in 1 .. 100 3 loop 4 for x in ( select username from all_users ) 5 loop 6 insert into heap 7 (username,document_name,other_data) values 8 ( x.username, x.username || _ || i, x ); 9 10 insert into iot 11 (username,document_name,other_data) values 12 ( x.username, x.username || _ || i, x ); 13 end loop; 14 end loop; 15 dbms_stats.gather_table_stats 16 ( user, IOT, cascade=>true ); 17 dbms_stats.gather_table_stats 18 ( user, HEAP, method_opt=>for all indexed columns, cascade=>true ); 19 commit; 20 end; 21 /
  11. 11. Organization Countsops$tkyte%ORA11GR2> declare 2 l_rec heap%rowtype; 3 cursor heap_cursor(p_username in varchar2) is 4 select * from heap single_row where username = p_username; 5 cursor iot_cursor(p_username in varchar2) is 6 select * from iot single_row where username = p_username; 7 begin 8 for i in 1 .. 10 9 loop 10 for x in (select username from all_users) loop 11 open heap_cursor(x.username); 12 loop 13 fetch heap_cursor into l_rec; 14 exit when heap_cursor%notfound; 15 end loop; 16 close heap_cursor; 17 open iot_cursor(x.username); 18 loop 19 fetch iot_cursor into l_rec; 20 exit when iot_cursor%notfound; 21 end loop; 22 close iot_cursor; 23 end loop; 24 end loop; 25 end; 26 /
  12. 12. Organization Counts ops$tkyte%ORA11GR2> declare 2 type array is table of iot%rowtype; 3 l_data array; 4 begin 5 for i in 1 .. 10 6 loop 7 for x in (select username from all_users) 8 loop 9 select * bulk collect into l_data 10 from heap bulk_collect 11 where username = x.username; 12 select * bulk collect into l_data 13 from iot bulk_collect 14 where username = x.username; 15 end loop; 16 end loop; 17 end; 18 / PL/SQL procedure successfully completed.
  13. 13. Organization CountsSELECT * FROM HEAP SINGLE_ROW WHERE USERNAME = :B1call count cpu elapsed disk query current rows------- ------ -------- ---------- ---------- ---------- ---------- ----------Parse 1 0.00 0.00 0 0 0 0Execute 410 0.02 0.02 0 0 0 0Fetch 41410 0.25 0.27 0 82810 0 41000------- ------ -------- ---------- ---------- ---------- ---------- ----------total 41821 0.28 0.30 0 82810 0 41000Row Source Operation---------------------------------------------------TABLE ACCESS BY INDEX ROWID HEAP (cr=202 pr=0 pw=0 time=41 us cost=102 ...) INDEX RANGE SCAN HEAP_PK (cr=102 pr=0 pw=0 time=221 us cost=2 size=0 ca...)
  14. 14. Organization CountsSELECT * FROM IOT SINGLE_ROW WHERE USERNAME = :B1call count cpu elapsed disk query current rows------- ------ -------- ---------- ---------- ---------- ---------- ----------Parse 1 0.00 0.00 0 0 0 0Execute 410 0.02 0.02 0 0 0 0Fetch 41410 0.16 0.18 0 42220 0 41000------- ------ -------- ---------- ---------- ---------- ---------- ----------total 41821 0.19 0.21 0 42220 0 41000Row Source Operation---------------------------------------------------INDEX RANGE SCAN IOT_PK (cr=103 pr=0 pw=0 time=33 us cost=21 size=102000 ...)
  15. 15. Organization CountsSELECT * FROM HEAP BULK_COLLECT WHERE USERNAME = :B1call count cpu elapsed disk query current rows------- ------ -------- ---------- ---------- ---------- ---------- ----------Parse 1 0.00 0.00 0 0 0 0Execute 410 0.01 0.02 0 0 0 0Fetch 410 0.11 0.12 0 42010 0 41000------- ------ -------- ---------- ---------- ---------- ---------- ----------total 821 0.13 0.14 0 42010 0 41000Row Source Operation---------------------------------------------------TABLE ACCESS BY INDEX ROWID HEAP (cr=102 pr=0 pw=0 time=533 us cost=102 ...) INDEX RANGE SCAN HEAP_PK (cr=2 pr=0 pw=0 time=23 us cost=2 size=0 ca...)
  16. 16. Organization CountsSELECT * FROM IOT BULK_COLLECT WHERE USERNAME = :B1call count cpu elapsed disk query current rows------- ------ -------- ---------- ---------- ---------- ---------- ----------Parse 1 0.00 0.00 0 0 0 0Execute 410 0.01 0.02 0 0 0 0Fetch 410 0.06 0.06 0 9000 0 41000------- ------ -------- ---------- ---------- ---------- ---------- ----------total 821 0.08 0.08 0 9000 0 41000Row Source Operation---------------------------------------------------INDEX RANGE SCAN IOT_PK (cr=22 pr=0 pw=0 time=142 us cost=21 size=102000...)
  17. 17. Knowing what is available•  There is a lot out there…•  I learn something new every day•  Skimming the docs works –  Oh, I remember something similar…•  Check out the “whats new in” at the head of the docs•  Participate in the forums•  Things change… Some things must be “discovered” Ignulls.sql
  18. 18. You have to learn new things…ops$tkyte%ORA11GR2> select dt, val 2 from t 3 order by dt;DT VAL--------- ----------02-JAN-11 19503-JAN-1104-JAN-1105-JAN-1106-JAN-11 12907-JAN-1108-JAN-1109-JAN-1110-JAN-11 8711-JAN-1110 rows selected.
  19. 19. You have to learn new things…ops$tkyte%ORA11GR2> select dt, val, 2 case when val is not null 3 then to_char(row_number() over (order by dt),fm0000)||val 4 end max_val 5 from t 6 order by dt;DT VAL MAX_VAL--------- ---------- ---------------------------------------------02-JAN-11 195 000119503-JAN-1104-JAN-1105-JAN-1106-JAN-11 129 000512907-JAN-1108-JAN-1109-JAN-1110-JAN-11 87 00098711-JAN-1110 rows selected.
  20. 20. You have to learn new things…ops$tkyte%ORA11GR2> select dt, val, 2 max(max_val) over (order by dt) max_val_str 3 from ( select dt, val, 4 case when val is not null 5 then to_char(row_number() over (order by dt),fm0000)||val 6 end max_val 7 from t ) order by dt 8 /DT VAL MAX_VAL_STR--------- ---------- ---------------------------------------------02-JAN-11 195 000119503-JAN-11 000119504-JAN-11 000119505-JAN-11 000119506-JAN-11 129 000512907-JAN-11 000512908-JAN-11 000512909-JAN-11 000512910-JAN-11 87 00098711-JAN-11 00098710 rows selected.
  21. 21. You have to learn new things…ops$tkyte%ORA11GR2> select dt, val, 2 to_number(substr(max(max_val) over (order by dt),5)) max_val 3 from ( select dt, val, 4 case when val is not null 5 then to_char(row_number() over (order by dt),fm0000)||val 6 end max_val 7 from t ) order by dt 8 /DT VAL MAX_VAL--------- ---------- ----------02-JAN-11 195 19503-JAN-11 19504-JAN-11 19505-JAN-11 19506-JAN-11 129 12907-JAN-11 12908-JAN-11 12909-JAN-11 12910-JAN-11 87 8711-JAN-11 8710 rows selected.
  22. 22. You have to learn new things…ops$tkyte%ORA11GR2> select dt, val, 2 last_value(val ignore nulls) over (order by dt) val 3 from t 4 order by dt 5 /DT VAL VAL--------- ---------- ----------02-JAN-11 195 19503-JAN-11 19504-JAN-11 19505-JAN-11 19506-JAN-11 129 12907-JAN-11 12908-JAN-11 12909-JAN-11 12910-JAN-11 87 8711-JAN-11 8710 rows selected.
  23. 23. Things Change begin for x in ( select * from big_table.big_table where rownum <= 10000 ) loop null; end loop; end;
  24. 24. Things Changedeclare type array is table of big_table%rowtype; l_data array; cursor c is select * from big_table where rownum <= 1000;begin open c; loop fetch c bulk collect into l_data limit 100; for i in 1 .. l_data.count loop null; end loop; exit when c%notfound; end loop; close c;end;
  25. 25. Things Change 9iSELECT * FROM BIG_TABLE.BIG_TABLE WHERE ROWNUM <= 10000call count cpu elapsed query rows------- ------ -------- ---------- ---------- ----------Parse 1 0.01 0.00 0 0Execute 1 0.00 0.00 0 0Fetch 10001 0.15 0.17 10005 10000------- ------ -------- ---------- ---------- ----------total 10003 0.16 0.17 10005 10000
  26. 26. Things Change 10gSELECT * FROM BIG_TABLE.BIG_TABLE WHERE ROWNUM <= 10000call count cpu elapsed query rows------- ------ -------- ---------- ---------- ----------Parse 1 0.00 0.00 0 0Execute 1 0.00 0.00 0 0Fetch 101 0.05 0.07 152 10000------- ------ -------- ---------- ---------- ----------total 103 0.05 0.07 152 10000
  27. 27. Using ROWNUM•  Psuedo Column – not a “real” column•  Assigned after the predicate (sort of during) but before any sort/aggregationSelect x,y from t where rownum < 10 order by xVersusSelect * from (select x,y from t order by x) where rownum < 10
  28. 28. Using ROWNUM•  Incremented after a successful outputSelect * from t where rownum = 2Rownum = 1For x in ( select * from t )Loop if ( rownum = 2 ) then output record rownum = rownum+1; end ifEnd loop
  29. 29. Using ROWNUM•  Top-N queriesSelect * from (select * from t where … order by X ) where rownum <= 10;•  Does not have to sort the entire set•  Sets up an “array” conceptually•  Gets the first 10•  When we get the 11th, see if it is in the top 10 –  If so, push out an existing array element, slide this in –  Else throw it out and get the next one.•  Do not attempt this in CODE! (well – what about 10g?) rn02.sql
  30. 30. Top-Nops$tkyte%ORA11GR2> explain plan for 2 select * from (select * from scott.emp order by sal desc) where rownum <= 10;Explained.ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display);PLAN_TABLE_OUTPUT--------------------------------------------------------------------------------------------------Plan hash value: 1744961472--------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 10 | 870 | 4 (25)| 00:00:01 ||* 1 | COUNT STOPKEY | | | | | || 2 | VIEW | | 14 | 1218 | 4 (25)| 00:00:01 ||* 3 | SORT ORDER BY STOPKEY| | 14 | 532 | 4 (25)| 00:00:01 || 4 | TABLE ACCESS FULL | EMP | 14 | 532 | 3 (0)| 00:00:01 |--------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 1 - filter(ROWNUM<=10) 3 - filter(ROWNUM<=10)17 rows selected.
  31. 31. Top-N ops$tkyte%ORA11GR2> @mystat "sorts (disk)" NAME VALUE ---------------------- ---------- sorts (disk) 0 ops$tkyte%ORA11GR2> select * 2 from (select * 3 from big_table.big_table 4 order by object_id) where rownum <= 10; 10 rows selected. Statistics ---------------------------------------------------------- … 1 sorts (memory) 0 sorts (disk) 10 rows processed ops$tkyte%ORA11GR2> @mystat2 NAME VALUE DIFF ---------------------- ---------- ------------------ sorts (disk) 0 0
  32. 32. Top-N ops$tkyte%ORA11GR2> @mystat "sorts (disk)" NAME VALUE ---------------------- ---------- sorts (disk) 0 ops$tkyte%ORA11GR2> declare 2 cursor c is 3 select * from big_table.big_table order by object_id; 4 l_rec big_table_v%rowtype; 5 begin 6 open c; 7 for i in 1 .. 10 8 loop 9 fetch c into l_rec; 10 end loop; 11 close c; 12 end; 13 / PL/SQL procedure successfully completed. ops$tkyte%ORA11GR2> @mystat2 NAME VALUE DIFF ---------------------- ---------- ------------------ sorts (disk) 1 1
  33. 33. Top-Nops$tkyte%ORA11GR2> create index bt_idx on big_table.big_table(object_id) ;Index created.
  34. 34. Top-Nselect * from (select * from big_table.big_table order by object_id) where rownum <= 10call count cpu elapsed disk query current rows------- ------ -------- ---------- ---------- ---------- ---------- ----------Parse 1 0.00 0.00 0 0 0 0Execute 1 0.00 0.00 0 0 0 0Fetch 2 0.00 0.00 2 14 0 10------- ------ -------- ---------- ---------- ---------- ---------- ----------total 4 0.00 0.00 2 14 0 10Misses in library cache during parse: 1Optimizer mode: ALL_ROWSParsing user id: 189Number of plan statistics captured: 1Row Source Operation---------------------------------------------------COUNT STOPKEY (cr=14 pr=2 pw=0 time=328 us) VIEW (cr=14 pr=2 pw=0 time=321 us cost=13 size=1410 card=10) TABLE ACCESS BY INDEX ROWID BIG_TABLE (cr=14 pr=2 pw=0 time=316 us …) INDEX FULL SCAN BT_IDX (cr=4 pr=2 pw=0 time=322 us cost=3 size=0 …)
  35. 35. Top-NSELECT * FROM BIG_TABLE.BIG_TABLE ORDER BY OBJECT_IDcall count cpu elapsed disk query current rows------- ------ -------- ---------- ---------- ---------- ---------- ----------Parse 1 0.00 0.00 0 0 0 0Execute 2 0.00 0.00 0 0 0 0Fetch 10 1.12 2.17 14703 14544 7 10------- ------ -------- ---------- ---------- ---------- ---------- ----------total 13 1.12 2.17 14703 14544 7 10Row Source Operation---------------------------------------------------SORT ORDER BY (cr=14544 pr=14703 pw=14639 time=2173284 us cost=26523 size...) TABLE ACCESS FULL BIG_TABLE (cr=14544 pr=14541 pw=0 time=694199 us cost=...)Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ direct path write temp 476 0.00 1.23 direct path read temp 6 0.00 0.00
  36. 36. Using ROWNUM•  PaginationSelect * From ( select a.*, ROWNUM rnum From ( your_query_goes_here ) a Where ROWNUM <= :MAX_ROW_TO_FETCH ) Where rnum >= :MIN_ROW_TO_FETCH;•  Everything from prior slide goes here…•  Never ever let them “count the rows”, never.•  Do not attempt this in CODE! rn03.sql
  37. 37. Paginationops$tkyte%ORA11GR2> set autotrace traceonly statisticsops$tkyte%ORA11GR2> variable max numberops$tkyte%ORA11GR2> variable min numberops$tkyte%ORA11GR2> exec :min := 100; :max := 115;PL/SQL procedure successfully completed.
  38. 38. Paginationselect * from (select a.*, rownum rnum from (select /*+ FIRST_ROWS(15) */ * from big_table.big_table order by object_id) a where rownum <= :Max) where rnum >= :mincall count cpu elapsed disk query current rows------- ------ -------- ---------- ---------- ---------- ---------- ----------Parse 1 0.00 0.00 0 0 0 0Execute 1 0.00 0.00 0 0 0 0Fetch 3 0.00 0.00 12 119 0 16------- ------ -------- ---------- ---------- ---------- ---------- ----------total 5 0.00 0.00 12 119 0 16Row Source Operation---------------------------------------------------VIEW (cr=119 pr=12 pw=0 time=939 us cost=18 size=2310 card=15) COUNT STOPKEY (cr=119 pr=12 pw=0 time=2840 us) VIEW (cr=119 pr=12 pw=0 time=2722 us cost=18 size=2115 card=15) TABLE ACCESS BY INDEX ROWID BIG_TABLE (cr=119 pr=12 pw=0 time=2605 us cost...) INDEX FULL SCAN BT_IDX (cr=4 pr=2 pw=0 time=258 us cost=3 size=0 card=...)
  39. 39. Paginationops$tkyte%ORA11GR2> declare 2 cursor c is 3 select * from big_table.big_table order by object_id; 4 l_rec big_table_v%rowtype; 5 begin 6 open c; 7 for i in 1 .. 115 8 loop 9 fetch c into l_rec; 10 if ( i < 100 ) 11 then 12 null; 13 else 14 null; -- process it 15 end if; 16 end loop; 17 close c; 18 end; 19 /PL/SQL procedure successfully completed.
  40. 40. PaginationSELECT * FROM BIG_TABLE.BIG_TABLE ORDER BY OBJECT_IDcall count cpu elapsed disk query current rows------- ------ -------- ---------- ---------- ---------- ---------- ----------Parse 1 0.00 0.00 0 0 0 0Execute 2 0.00 0.00 0 0 0 0Fetch 115 1.20 2.32 14703 14544 7 115------- ------ -------- ---------- ---------- ---------- ---------- ----------total 118 1.21 2.32 14703 14544 7 115Row Source Operation---------------------------------------------------SORT ORDER BY (cr=14544 pr=14703 pw=14639 time=2324724 us cost=26523 size=...) TABLE ACCESS FULL BIG_TABLE (cr=14544 pr=14541 pw=0 time=682159 us cost=...)Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ direct path write temp 571 0.00 1.34 direct path read temp 6 0.00 0.00
  41. 41. Scalar Subqueries•  The ability to use a single column, single row query where you would normally use a “value”Select dname, ‘Some Value’From dept•  That example shows a possible use of scalar subquerys – outer join removal
  42. 42. Scalar Subqueries•  The ability to use a single column, single row query where you would normally use a “value”Select dname, (select count(*) from emp where emp.deptno = :dept.deptno ) cntFrom dept•  That example shows a possible use of scalar subquerys – outer join removal
  43. 43. Scalar Subqueries•  Outer join removal for “fast return” queries –  That works great for a single column –  What about when you need more than one? ss01.sql
  44. 44. Scalar Subqueriesops$tkyte%ORA11GR2> select * 2 from ( 3 select a.owner, count(b.owner) 4 from big_table.big_table_owners a left join big_table.big_table b 5 on (a.owner = b.owner and b.object_type = TABLE ) 6 group by a.owner 7 order by a.owner 8 ) 9 where rownum <= 2 10 /Statistics---------------------------------------------------------- 14613 consistent gets 14541 physical reads 7 sorts (memory) 0 sorts (disk) 2 rows processed
  45. 45. Scalar Subqueriesops$tkyte%ORA11GR2> select a.*, 2 (select count(*) 3 from big_table.big_table b 4 where b.owner = a.owner and b.object_type = TABLE ) cnt 5 from ( 6 select a.owner 7 from big_table.big_table_owners a 8 order by a.owner 9 ) a 10 where rownum <= 2 11 /Statistics---------------------------------------------------------- 590 consistent gets 1 sorts (memory) 0 sorts (disk) 2 rows processed
  46. 46. Scalar Subqueriesops$tkyte%ORA11GR2> select a.*, 2 (select count(*) 3 from big_table.big_table b 4 where b.owner = a.owner and b.object_type = TABLE ) cnt, 5 (select min(created) 6 from big_table.big_table b 7 where b.owner = a.owner and b.object_type = TABLE ) min_created, 8 (select max(created) 9 from big_table.big_table b 10 where b.owner = a.owner and b.object_type = TABLE ) max_created 11 from ( 12 select a.owner 13 from big_table.big_table_owners a 14 order by a.owner 15 ) a 16 where rownum <= 2 17 /Statistics---------------------------------------------------------- 1766 consistent gets 1 sorts (memory) 0 sorts (disk) 2 rows processed
  47. 47. Scalar Subqueriesops$tkyte%ORA11GR2> select owner, 2 to_number(substr(data,1,10)) cnt, 3 to_date(substr(data,11,14),yyyymmddhh24miss) min_created, 4 to_date(substr(data,25),yyyymmddhh24miss) max_created 5 from ( 6 select owner, 7 (select to_char( count(*), fm0000000000) || 8 to_char( min(created),yyyymmddhh24miss) || 9 to_char( max(created),yyyymmddhh24miss) 10 from big_table.big_table b 11 where b.owner = a.owner and b.object_type = TABLE ) data 12 from ( 13 select a.owner 14 from big_table.big_table_owners a 15 order by a.owner 16 ) a 17 where rownum <= 2 18 ) 19 /Statistics---------------------------------------------------------- 590 consistent gets 1 sorts (memory) 0 sorts (disk) 2 rows processed
  48. 48. Scalar Subqueriesops$tkyte%ORA11GR2> create or replace type myType as object 2 ( cnt number, min_created date, max_created date ) 3 /Type created.
  49. 49. Scalar Subqueriesops$tkyte%ORA11GR2> select owner, a.data.cnt, a.data.min_created, a.data.max_created 2 from ( 3 select owner, 4 (select myType( count(*), min(created), max(created) ) 5 from big_table.big_table b 6 where b.owner = a.owner and b.object_type = TABLE ) data 7 from ( 8 select a.owner 9 from big_table.big_table_owners a 10 order by a.owner 11 ) a 12 where rownum <= 2 13 ) a 14 /Statistics---------------------------------------------------------- 590 consistent gets 1 sorts (memory) 0 sorts (disk) 2 rows processed
  50. 50. Scalar Subqueries•  Reducing PLSQL function calls via scalar subquery cachingSelect * from t where x = pkg.getval()versusSelect * from t where x = (select pkg.getval() from dual)•  How to call them (scalar subqueries) “as little as possible” ss02.sql
  51. 51. Scalar Subqueriesops$tkyte%ORA11GR2> create or replace function f( x in varchar2 ) return number 2 as 3 begin 4 dbms_application_info.set_client_info(userenv(client_info)+1 ); 5 return length(x); 6 end; 7 /Function created.
  52. 52. Scalar Subqueriesops$tkyte%ORA11GR2> exec :cpu := dbms_utility.get_cpu_time; dbms_application_info.set_client_info(0);PL/SQL procedure successfully completed.ops$tkyte%ORA11GR2> select owner, f(owner) from stage;72841 rows selected.ops$tkyte%ORA11GR2> select dbms_utility.get_cpu_time-:cpu cpu_hsecs, userenv(client_info) from dual; CPU_HSECS USERENV(CLIENT_INFO)---------- ---------------------------------------------------------- 111 72841
  53. 53. Scalar Subqueriesops$tkyte%ORA11GR2> exec :cpu := dbms_utility.get_cpu_time; dbms_application_info.set_client_info(0);PL/SQL procedure successfully completed.ops$tkyte%ORA11GR2> select owner, (select f(owner) from dual) f from stage;72841 rows selected.ops$tkyte%ORA11GR2> select dbms_utility.get_cpu_time-:cpu cpu_hsecs, userenv(client_info) from dual; CPU_HSECS USERENV(CLIENT_INFO)---------- -------------------------------------------- 30 66
  54. 54. Scalar Subqueriesops$tkyte%ORA11GR2> exec :cpu := dbms_utility.get_cpu_time; dbms_application_info.set_client_info(0);PL/SQL procedure successfully completed.ops$tkyte%ORA11GR2> select owner, (select f(owner) from dual) f 2 from (select owner, rownum r from stage order by owner);72841 rows selected.ops$tkyte%ORA11GR2> select dbms_utility.get_cpu_time-:cpu cpu_hsecs, userenv(client_info) from dual; CPU_HSECS USERENV(CLIENT_INFO)---------- -------------------------------------------------------------- 32 32
  55. 55. Scalar Subqueriesops$tkyte%ORA11GR2> create or replace function f( x in varchar2 ) return number 2 DETERMINISTIC 3 as 4 begin 5 dbms_application_info.set_client_info(userenv(client_info)+1 ); 6 return length(x); 7 end; 8 /Function created.
  56. 56. Scalar Subqueriesops$tkyte%ORA11GR2> exec :cpu := dbms_utility.get_cpu_time; dbms_application_info.set_client_info(0);PL/SQL procedure successfully completed.ops$tkyte%ORA11GR2> select owner, f(owner) from stage;72841 rows selected.ops$tkyte%ORA11GR2> select dbms_utility.get_cpu_time-:cpu cpu_hsecs, userenv(client_info) from dual; CPU_HSECS USERENV(CLIENT_INFO)---------- -------------------------------------------------------------- 73 8316
  57. 57. Scalar Subqueriesops$tkyte%ORA11GR2> create or replace function f( x in varchar2 ) return number 2 RESULT_CACHE 3 as 4 begin 5 dbms_application_info.set_client_info(userenv(client_info)+1 ); 6 return length(x); 7 end; 8 /Function created.
  58. 58. Scalar Subqueriesops$tkyte%ORA11GR2> exec :cpu := dbms_utility.get_cpu_time; dbms_application_info.set_client_info(0);PL/SQL procedure successfully completed.ops$tkyte%ORA11GR2> select owner, f(owner) from stage;72841 rows selected.ops$tkyte%ORA11GR2> select dbms_utility.get_cpu_time-:cpu cpu_hsecs, userenv(client_info) from dual; CPU_HSECS USERENV(CLIENT_INFO)---------- ---------------------------------------------------------- 64 32
  59. 59. Scalar Subqueriesops$tkyte%ORA11GR2> exec :cpu := dbms_utility.get_cpu_time; dbms_application_info.set_client_info(0);PL/SQL procedure successfully completed.ops$tkyte%ORA11GR2> select owner, f(owner) from stage;72841 rows selected.ops$tkyte%ORA11GR2> select dbms_utility.get_cpu_time-:cpu cpu_hsecs, userenv(client_info) from dual; CPU_HSECS USERENV(CLIENT_INFO)---------- ----------------------------------------------------------- 69 0
  60. 60. Scalar Subqueriesops$tkyte%ORA11GR2> exec :cpu := dbms_utility.get_cpu_time; dbms_application_info.set_client_info(0);PL/SQL procedure successfully completed.ops$tkyte%ORA11GR2> select owner, (select f(owner) from dual) from stage;72841 rows selected.ops$tkyte%ORA11GR2> select dbms_utility.get_cpu_time-:cpu cpu_hsecs, user CPU_HSECS USERENV(CLIENT_INFO)---------- -------------------------------------------------------------- 19 0
  61. 61. Don’t tune queries!
  62. 62. Think in SETS!
  63. 63. Questions

×