63
Some SQL Techniques

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

Embed Size (px)

DESCRIPTION

 

Citation preview

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

Some SQL Techniques

Page 2: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

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

Page 3: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

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 –  …

Page 4: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

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”

Page 5: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Structures

•  How the data is accessed and organized makes a difference

–  Clustering

Select *

from orders o, line_items li

where o.order# = li.order#

And o.order# = :order

ORDERS LINE ITEMS

ORDERS & LINE ITEMS

Page 6: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

STOCKS

Structures

•  How the data is accessed and organized makes a difference

–  Clustering –  Index Organized Tables

Select avg(price)

From stocks

Where symbol = ‘ORCL’

And stock_dt >= sysdate-5;

STOCKS

Page 7: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Structures

•  How the data is accessed and organized makes a difference

–  Clustering –  Index Organized Tables –  Partitioning

Large Table Difficult to Manage

ORDERS

Partition Divide and Conquer Easier to Manage Improve Performance

ORDERS

Jan Feb Composite Partition Higher Performance More flexibility to match business needs

ORDERS

Jan Feb

Europe

USA

Page 8: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

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

Page 9: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Organization Counts

ops$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.

Page 10: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Organization Counts ops$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 /

Page 11: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Organization Counts ops$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 /

Page 12: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

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.

Page 13: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Organization Counts

SELECT * FROM HEAP SINGLE_ROW WHERE USERNAME = :B1 call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 410 0.02 0.02 0 0 0 0 Fetch 41410 0.25 0.27 0 82810 0 41000 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 41821 0.28 0.30 0 82810 0 41000 Row 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...)

Page 14: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Organization Counts

SELECT * FROM IOT SINGLE_ROW WHERE USERNAME = :B1 call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 410 0.02 0.02 0 0 0 0 Fetch 41410 0.16 0.18 0 42220 0 41000 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 41821 0.19 0.21 0 42220 0 41000 Row Source Operation --------------------------------------------------- INDEX RANGE SCAN IOT_PK (cr=103 pr=0 pw=0 time=33 us cost=21 size=102000 ...)

Page 15: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Organization Counts

SELECT * FROM HEAP BULK_COLLECT WHERE USERNAME = :B1 call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 410 0.01 0.02 0 0 0 0 Fetch 410 0.11 0.12 0 42010 0 41000 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 821 0.13 0.14 0 42010 0 41000 Row 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...)

Page 16: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Organization Counts

SELECT * FROM IOT BULK_COLLECT WHERE USERNAME = :B1 call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 410 0.01 0.02 0 0 0 0 Fetch 410 0.06 0.06 0 9000 0 41000 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 821 0.08 0.08 0 9000 0 41000 Row Source Operation --------------------------------------------------- INDEX RANGE SCAN IOT_PK (cr=22 pr=0 pw=0 time=142 us cost=21 size=102000...)

Page 17: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

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

Page 18: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

You have to learn new things…

ops$tkyte%ORA11GR2> select dt, val 2 from t 3 order by dt; DT VAL --------- ---------- 02-JAN-11 195 03-JAN-11 04-JAN-11 05-JAN-11 06-JAN-11 129 07-JAN-11 08-JAN-11 09-JAN-11 10-JAN-11 87 11-JAN-11 10 rows selected.

Page 19: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

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 0001195 03-JAN-11 04-JAN-11 05-JAN-11 06-JAN-11 129 0005129 07-JAN-11 08-JAN-11 09-JAN-11 10-JAN-11 87 000987 11-JAN-11 10 rows selected.

Page 20: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

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 0001195 03-JAN-11 0001195 04-JAN-11 0001195 05-JAN-11 0001195 06-JAN-11 129 0005129 07-JAN-11 0005129 08-JAN-11 0005129 09-JAN-11 0005129 10-JAN-11 87 000987 11-JAN-11 000987 10 rows selected.

Page 21: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

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 195 03-JAN-11 195 04-JAN-11 195 05-JAN-11 195 06-JAN-11 129 129 07-JAN-11 129 08-JAN-11 129 09-JAN-11 129 10-JAN-11 87 87 11-JAN-11 87 10 rows selected.

Page 22: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

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 195 03-JAN-11 195 04-JAN-11 195 05-JAN-11 195 06-JAN-11 129 129 07-JAN-11 129 08-JAN-11 129 09-JAN-11 129 10-JAN-11 87 87 11-JAN-11 87 10 rows selected.

Page 23: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Things Change

begin for x in ( select * from big_table.big_table where rownum <= 10000 ) loop null; end loop; end;

Page 24: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Things Change declare 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;

Page 25: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Things Change 9i

SELECT * FROM BIG_TABLE.BIG_TABLE WHERE ROWNUM <= 10000 call count cpu elapsed query rows ------- ------ -------- ---------- ---------- ---------- Parse 1 0.01 0.00 0 0 Execute 1 0.00 0.00 0 0 Fetch 10001 0.15 0.17 10005 10000 ------- ------ -------- ---------- ---------- ---------- total 10003 0.16 0.17 10005 10000

Page 26: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Things Change 10g

SELECT * FROM BIG_TABLE.BIG_TABLE WHERE ROWNUM <= 10000 call count cpu elapsed query rows ------- ------ -------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 Execute 1 0.00 0.00 0 0 Fetch 101 0.05 0.07 152 10000 ------- ------ -------- ---------- ---------- ---------- total 103 0.05 0.07 152 10000

Page 27: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Using ROWNUM

•  Psuedo Column – not a “real” column •  Assigned after the predicate (sort of during) but

before any sort/aggregation

Select x,y from t where rownum < 10 order by x Versus Select * from (select x,y from t order by x) where rownum < 10

Page 28: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Using ROWNUM •  Incremented after a successful output Select * from t where rownum = 2 Rownum = 1 For x in ( select * from t ) Loop if ( rownum = 2 ) then output record rownum = rownum+1; end if End loop

Page 29: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Using ROWNUM •  Top-N queries Select * 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

Page 30: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Top-N ops$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.

Page 31: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

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

Page 32: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

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

Page 33: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Top-N

ops$tkyte%ORA11GR2> create index bt_idx on big_table.big_table(object_id) ; Index created.

Page 34: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Top-N select * from (select * from big_table.big_table order by object_id) where rownum <= 10 call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 2 0.00 0.00 2 14 0 10 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 4 0.00 0.00 2 14 0 10 Misses in library cache during parse: 1 Optimizer mode: ALL_ROWS Parsing user id: 189 Number of plan statistics captured: 1 Row 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 …)

Page 35: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Top-N

SELECT * FROM BIG_TABLE.BIG_TABLE ORDER BY OBJECT_ID call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 2 0.00 0.00 0 0 0 0 Fetch 10 1.12 2.17 14703 14544 7 10 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 13 1.12 2.17 14703 14544 7 10 Row 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

Page 36: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Using ROWNUM

•  Pagination

Select * 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

Page 37: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Pagination

ops$tkyte%ORA11GR2> set autotrace traceonly statistics ops$tkyte%ORA11GR2> variable max number ops$tkyte%ORA11GR2> variable min number ops$tkyte%ORA11GR2> exec :min := 100; :max := 115; PL/SQL procedure successfully completed.

Page 38: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Pagination

select * 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 >= :min call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 3 0.00 0.00 12 119 0 16 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 5 0.00 0.00 12 119 0 16 Row 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=...)

Page 39: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Pagination 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 .. 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.

Page 40: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Pagination

SELECT * FROM BIG_TABLE.BIG_TABLE ORDER BY OBJECT_ID call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 2 0.00 0.00 0 0 0 0 Fetch 115 1.20 2.32 14703 14544 7 115 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 118 1.21 2.32 14703 14544 7 115 Row 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

Page 41: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

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

Page 42: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

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 ) cnt From dept •  That example shows a possible use of scalar

subquerys – outer join removal

Page 43: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

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

Page 44: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries

ops$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

Page 45: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries

ops$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

Page 46: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries ops$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

Page 47: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries ops$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

Page 48: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries

ops$tkyte%ORA11GR2> create or replace type myType as object 2 ( cnt number, min_created date, max_created date ) 3 / Type created.

Page 49: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries ops$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

Page 50: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries

•  Reducing PLSQL function calls via scalar subquery caching

Select * from t where x = pkg.getval() versus Select * from t where x = (select pkg.getval() from dual) •  How to call them (scalar subqueries) “as little as

possible” ss02.sql

Page 51: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries

ops$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.

Page 52: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries

ops$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

Page 53: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries

ops$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

Page 54: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries

ops$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

Page 55: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries

ops$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.

Page 56: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries

ops$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

Page 57: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries

ops$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.

Page 58: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries

ops$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

Page 59: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries

ops$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

Page 60: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Scalar Subqueries

ops$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, userenv('client_info') from dual; CPU_HSECS USERENV('CLIENT_INFO') ---------- ---------------------------------------------------------------- 19 0

Page 61: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Don’t tune queries!

Page 62: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Think in SETS!

Page 63: Database & Technology 1 _ Tom Kyte _ SQL Techniques.pdf

Questions