358
NOTE itty bitty fonts in this presentation SQL> exec sample_font Can you read this ? 1

NOTE itty bitty fonts in this presentation SQL> select PASSPORT_PHOTO 2 from PERSON 3 where surname = 'MCDONALD' 4 / SP2-0678: Column type can not be displayed by SQL*Plus ... 38 SQL>

Embed Size (px)

Citation preview

NOTE

itty bitty fonts in this

presentation

SQL> exec sample_font

Can you read this ?

1

Connor McDonald

OracleDBA

co

.uk

2

3

bio slide

4

5

6

7

"why bother?"

8

2008 2009 2010 2011 2012 2013 2014 2016 2017

11g 11.1.0.7 11.2

management

visibility

11g

desupported

11.1.0.6

"why bother?"

(part 2)

10

don’t reinvent

13

there's a lot in 11g !

14

some cool things....

15

some not so cool things....

16

g1

g2

g3

17

"11g is now production"

18

19

11g ≠

20

21

cool-ness barometer

22

first impressions

23

24

ORA-01017: invalid username/password; logon denied

25

ORA-28000: the account is locked

26

case sensitive passwords

27

default profile tightened

28

password complexity

29

be patient

30

31

snippets

32

snippets #1:

sqlplus BLOBS

33

10g and below

34

SQL> select PASSPORT_PHOTO

2 from PERSON

3 where surname = 'MCDONALD'

4 /

SP2-0678: Column type can not be displayed by SQL*Plus

35

SQL> select PASSPORT_PHOTO

2 from PERSON

3 where surname = 'MCDONALD'

4 /

MUGSHOT_BLOB

-----------------------------------------------------

D0CF11E0A1B11AE1000000000000000000000000000000003E000

02300000001000000FEFFFFFF0000000020000000

null versus empty_blob()

36

snippets #2:

sqlplus error logging

37

SQL> set errorlogging on

38

SQL> set errorlogging on

SQL> desc SPERRORLOG

Name Type

------------------------------------- ----------------

USERNAME VARCHAR2(256)

TIMESTAMP TIMESTAMP(6)

SCRIPT VARCHAR2(1024)

IDENTIFIER VARCHAR2(256)

MESSAGE CLOB

STATEMENT CLOB

39

SQL> select * from THE_WRONG_NAME;

select * from THE_WRONG_NAME

*

ERROR at line 1:

ORA-00942: table or view does not exist

SQL> desc THE_WRONG_NAME;

ERROR:

ORA-04043: object THE_WRONG_NAME does not exist

SQL> grant execute on P to NOT_A_USER;

grant execute on P to NOT_A_USER

*

ERROR at line 1:

ORA-01917: user or role 'NOT_A_USER' does not exist

40

SQL> select timestamp, message, statement

2 from SPERRORLOG;

TIMESTAMP

-----------------------------------------------------

MESSAGE

-----------------------------------------------------

STATEMENT

-----------------------------------------------------

01-APR-08 02.29.58.000000 PM

ORA-00942: table or view does not exist

select * from THE_WRONG_NAME

01-APR-08 02.29.58.000000 PM

ORA-04043: object THE_WRONG_NAME does not exist

desc THE_WRONG_NAME;

01-APR-08 02.30.04.000000 PM

ORA-01917: user or role "NOT_A_USER" does not exist

grant execute on P to NOT_A_USER

41

installation scripts

SQL> set errorlogging on

SQL> @create_all_objects

works on 10g too…

42

snippets #3:

sqlplus transaction safety

43

44

SQL> set exitcommit

45

snippets #4:

dbms_utility.get_sql_hash

46

SQL> select hash_value

2 from v$sql

3 where sql_text = 'SELECT 99 FROM DUAL';

HASH_VALUE

----------

835694897

47

SQL> declare

2 h1 raw(16);

3 h2 number;

4 n int;

5 begin

6 n :=

7 dbms_utility.get_sql_hash(

8 'SELECT 99 FROM DUAL' ,h1,h2);

9 dbms_output.put_line(h1);

10 end;

11 /

F1D44D227DC0C4E0C719280B31B1CF3131B1CF31

= 835694897

||chr(0)

48

snippets #5:

listagg

classical problem

49

SQL> select deptno, ename

2 from emp

3 order by 1,2;

DEPTNO ENAME

---------- ----------

10 CLARK

10 KING

10 MILLER

20 ADAMS

20 FORD

20 JONES

20 SCOTT

20 SMITH

30 ALLEN

30 BLAKE

30 JAMES

30 MARTIN

30 TURNER

30 WARD

50

DEPTNO MEMBERS

---------- -------------------------------------

10 CLARK,KING,MILLER

20 SMITH,JONES,SCOTT,ADAMS,FORD

30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES

51

SQL> select deptno , rtrim(ename,',') enames

2 from ( select deptno,ename,rn

3 from emp

4 model

5 partition by (deptno)

6 dimension by (

7 row_number() over

8 (partition by deptno order by ename) rn

9 )

10 measures (cast(ename as varchar2(40)) ename)

11 rules

12 ( ename[any]

13 order by rn desc = ename[cv()]||','||ename[cv()+1])

14 )

15 where rn = 1

16 order by deptno;

DEPTNO ENAMES

---------- ----------------------------------------

10 CLARK,KING,MILLER

20 ADAMS,FORD,JONES,SCOTT,SMITH

30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD

52- Rob Van Wijk

SQL> select deptno,

2 substr(max(sys_connect_by_path(ename, ',')), 2) members

3 from (select deptno, ename,

4 row_number ()

5 over (partition by deptno order by empno) rn

6 from emp)

7 start with rn = 1

8 connect by prior rn = rn - 1

9 and prior deptno = deptno

10 group by deptno

11 /

DEPTNO MEMBERS

---------- ---------------------------------------------------------

30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES

20 SMITH,JONES,SCOTT,ADAMS,FORD

10 CLARK,KING,MILLER

53- Anon

SQL> select deptno,

2 xmltransform

3 ( sys_xmlagg

4 ( sys_xmlgen(ename)

5 ),

6 xmltype

7 (

8 '<?xml version="1.0"?><xsl:stylesheet version="1.0"

9 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

10 <xsl:template match="/">

11 <xsl:for-each select="/ROWSET/ENAME">

12 <xsl:value-of select="text()"/>;</xsl:for-each>

13 </xsl:template>

14 </xsl:stylesheet>'

15 )

16 ).getstringval() members

17 from emp

18 group by deptno;

DEPTNO MEMBERS

---------- --------------------------------------------------------

10 CLARK;MILLER;KING;

20 SMITH;FORD;ADAMS;SCOTT;JONES;

30 ALLEN;JAMES;TURNER;BLAKE;MARTIN;WARD;

54- Laurent Schneider

SQL> create or replace type string_agg_type as object

2 (

3 total varchar2(4000),

4

5 static function

6 ODCIAggregateInitialize(sctx IN OUT string_agg_type )

7 return number,

8

9 member function

10 ODCIAggregateIterate(self IN OUT string_agg_type ,

11 value IN varchar2 )

12 return number,

13

14 member function

15 ODCIAggregateTerminate(self IN string_agg_type,

16 returnValue OUT varchar2,

17 flags IN number)

18 return number,

19

20 member function

21 ODCIAggregateMerge(self IN OUT string_agg_type,

22 ctx2 IN string_agg_type)

23 return number

24 );

25 /55- Tom Kyte

56

SQL> select deptno,

2 listagg( ename, ',')

3 within group (order by empno) members

4 from emp

5 group by deptno;

DEPTNO MEMBERS

---------- -----------------------------------------

10 CLARK,KING,MILLER

20 SMITH,JONES,SCOTT,ADAMS,FORD

30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES

57

Feature:

real time sql monitoring

58

59

60

select e.department_id, sum(salary)

from emp e,

job_hist j

where e.employee_id = j.employee_id

and extract(year from e.hire_date) > 1985

and j.end_date > j.start_date + 1

and j.start_date >= e.hire_date

group by e.department_id

61

v$sql_plan

-----------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)|

-----------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 36M| 2742M| | 10998 (48)|

| 1 | HASH GROUP BY | | 36M| 2742M| | 10998 (48)|

|* 2 | HASH JOIN | | 36M| 2742M| 3728K| 9137 (37)|

|* 3 | TABLE ACCESS FULL| JOB_HIST | 88761 | 2687K| | 147 (3)|

|* 4 | TABLE ACCESS FULL| EMP | 877K| 40M| | 3028 (2)|

-----------------------------------------------------------------------------

62

63

SQL> select

2 DBMS_SQLTUNE.REPORT_SQL_MONITOR(

3 sql_id=>'d3ncuxj7629bf',

4 report_level=>'ALL',

5 type=>'HTML') as report

6 from dual;

64

68

11.2.0.2

SQL> select

2 DBMS_SQLTUNE.REPORT_SQL_DETAIL(

3 sql_id=>'d3ncuxj7629bf',

4 report_level=>'ALL',

5 type=>'ACTIVE') as report

6 from dual;

69

70

71

Feature:

statistics enhancements

71

72

73

74

cardinality is everything

74

75

same with Oracle

75

76

some real(ish) data

76

77

SQL> desc VEHICLE

Name Null? Type

-------------------------- -------- -------------

ID NUMBER

MAKE VARCHAR2(6)

MODEL VARCHAR2(6)

SQL> select count(*)

2 from VEHICLE;

COUNT(*)

------------

2,157,079

77

78

default stats not enough

78

79

SQL> select count(*)

2 from VEHICLE

3 where MAKE = 'HOLDEN';

COUNT(*)

----------

415387

------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost |

------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 7 | 138|

| 1 | SORT AGGREGATE | | 1 | 7 | |

|* 2 | INDEX RANGE SCAN| MAKE_IX | 55310 | 378K| 138|

------------------------------------------------------------

79

80

histogram

80

81

SQL> begin

2 dbms_stats.gather_table_stats(user,'VEHICLE',

3 method_opt=>'for all columns size 1,'||

4 'for columns MAKE size 254,'||

5 'for columns MODEL size 254');

6 end;

7 /

PL/SQL procedure successfully completed.

81

82

SQL> select count(*)

2 from VEHICLE

3 where MAKE = 'HOLDEN';

COUNT(*)

----------

415387

-----------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost |

-----------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 7 | 1024|

| 1 | SORT AGGREGATE | | 1 | 7 | |

|* 2 | INDEX RANGE SCAN| MAKE_IX | 418K| 2859K| 1024|

-----------------------------------------------------------

82

83

make AND model

83

84

SQL> select count(*)

2 from VEHICLE

3 where MAKE = 'HOLDEN'

4 and MODEL = 'COMMODORE';

COUNT(*)

----------

214468

--------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes |

---------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 14 |

| 1 | SORT AGGREGATE | | 1 | 14 |

| 2 | BITMAP CONVERSION COUNT | | 39527 | 540K|

| 3 | BITMAP AND | | | |

| 4 | BITMAP CONVERSION FROM ROWIDS| | | |

|* 5 | INDEX RANGE SCAN | MODEL_IX | | |

| 6 | BITMAP CONVERSION FROM ROWIDS| | | |

|* 7 | INDEX RANGE SCAN | MAKE_IX | | |

---------------------------------------------------------------------

84

50% holdens are commodores

85

two things

85

86

8787

88

no correlation

10g and before

88

89

----------------------------------------------------------

| Id | Operation | Rows | Bytes |

----------------------------------------------------------

| 0 | SELECT STATEMENT | 1 | 14 |

| 1 | SORT AGGREGATE | 1 | 14 |

| 2 | BITMAP CONVERSION COUNT | 39527 | 540K|

89

90

SQL> select count(*) from VEHICLE where model = 'COMMODORE';

COUNT(*)

----------

214468

SQL> select count(*) from VEHICLE where make = 'HOLDEN';

COUNT(*)

----------

415387

SQL> select (214468/2157079)*

2 (415387/2157079)*

3 2157079 EST_ROWS from dual;

EST_ROWS

---------------

41299.9334 ≈ 39527

Prob(xy)=Prob(x)*Prob(y)

90

91

SQL> select

2 DBMS_STATS.CREATE_EXTENDED_STATS(

3 user, 'VEHICLE','(MAKE,MODEL)') tag

4 from dual;

TAG

----------------------------------

SYS_STU8QPK2S$PEWHARK2CP3#1F#G

SQL> select COLUMN_NAME,NUM_DISTINCT

2 from user_tab_cols

3 where table_name = 'VEHICLE'

COLUMN_NAME NUM_DISTINCT

------------------------------ ------------

ID 2157079

MAKE 39

MODEL 292

SYS_STU8QPK2S$PEWHARK2CP3#1F#G

91

92

SQL> begin

2 dbms_stats.gather_table_stats(user,'VEHICLE',

3 method_opt=>

4 'for columns SYS_STU8QPK2S$PEWHARK2CP3#1F#G size 254');

5 end;

6 /

PL/SQL procedure successfully completed.

SQL> begin

2 dbms_stats.gather_table_stats(user,'VEHICLE',

3 method_opt=>

4 'for columns (make,model) size 254');

5 end;

6 /

PL/SQL procedure successfully completed.

92

93

SQL> select count(*)

2 from VEHICLE

3 where MAKE = 'HOLDEN'

4 and MODEL = 'COMMODORE';

COUNT(*)

----------

214468

-------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost |

------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 14 | 1956|

| 1 | SORT AGGREGATE | | 1 | 14 | |

|* 2 | TABLE ACCESS FULL| VEHICLE | 220K| 3018K| 1956|

-------------------------------------------------------------

93

9494

actual versus estimate

95

SQL> select /*+ GATHER_PLAN_STATISTICS */ count(*)

2 from VEHICLE

3 where MAKE = 'HOLDEN'

4 and MODEL = 'COMMODORE';

COUNT(*)

----------

214468

SQL> SELECT *

2 FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(

3 NULL, NULL, 'ALLSTATS LAST'));

----------------------------------------------------------------

| Id | Operation | Name | Starts | E-Rows | A-Rows |

----------------------------------------------------------------

| 1 | SORT AGGREGATE | | 1 | 1 | 1 |

|* 2 | TABLE ACCESS FULL| VEHICLE | 1 | 220K| 214K|

-----------------------------------------------------------------

95

96

its just another column

96

97

SQL> select "SYS_STU8QPK2S$PEWHARK2CP3#1F#G"

2 from vehicle

3 where rownum < 10;

SYS_STU8QPK2S$PEWHARK2CP3#1F#G

------------------------------

1.2706E+19

1.8075E+19

7.9949E+18

1.1730E+19

6.7142E+18

1.1730E+19

1.0779E+19

5.4051E+18

7.3555E+18

97

98

forget ...

98

99

SQL> SELECT extension_name, extension

2 FROM USER_STAT_EXTENSIONS

3 WHERE table_name = 'VEHICLE';

EXTENSION_NAME EXTENSION

------------------------------ -----------------

SYS_STU8QPK2S$PEWHARK2CP3#1F#G ("MAKE","MODEL")

99

100

SQL> select SYS_OP_COMBINED_HASH(make,model) hashval,

2 "SYS_STU8QPK2S$PEWHARK2CP3#1F#G" colval

3 from VEHICLE

4 where rownum < 10;

HASHVAL COLVAL

---------- ----------

1.2706E+19 1.2706E+19

1.8075E+19 1.8075E+19

7.9949E+18 7.9949E+18

1.1730E+19 1.1730E+19

6.7142E+18 6.7142E+18

1.1730E+19 1.1730E+19

1.0779E+19 1.0779E+19

5.4051E+18 5.4051E+18

7.3555E+18 7.3555E+18

100

101

PARSING IN CURSOR #28

alter table "SH"."VEHICLE" add

(SYS_STU8QPK2S$PEWHARK2CP3#1F#G

as (SYS_OP_COMBINED_HASH(MAKE,MODEL))

virtual BY USER for statistics);

END OF STMT

101

102

virtual column

102

103103

SYS_OP_COMBINED_HASH

104

hash means equality

104

105

SQL> select count(*)

2 from VEHICLE

3 where MAKE in ('FORD','HOLDEN')

4 and MODEL = 'COMMODORE';

COUNT(*)

----------

214468

-----------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost

-----------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 14 | 1921

| 1 | SORT AGGREGATE | | 1 | 14 |

|* 2 | VIEW | index$_join$_001 | 77818 | 1063K| 1921

|* 3 | HASH JOIN | | | |

|* 4 | INDEX RANGE SCAN | MODEL_IX | 77818 | 1063K| 502

| 5 | INLIST ITERATOR | | | |

|* 6 | INDEX RANGE SCAN| MAKE_IX | 77818 | 1063K| 2086

-----------------------------------------------------------------------

105

106

can we solve this ?

106

107

two enhancements

107

108

adaptive cursor sharing

11.1

108

109

11.2

109

much

110

much

better

111

112112

recall

113113

cardinality

114114

actual versus estimate

115115

employ someone....

116

SQL> select /*+ GATHER_PLAN_STATISTICS */ count(*)

2 from VEHICLE

3 where MAKE = 'HOLDEN'

4 and MODEL = 'COMMODORE';

COUNT(*)

----------

214468

SQL> SELECT *

2 FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(

3 NULL, NULL, 'ALLSTATS LAST'));

-----------------------------------------------------------------

| Id | Operation | Name | Starts | E-Rows | A-Rows |

-----------------------------------------------------------------

| 1 | SORT AGGREGATE | | 1 | 1 | 1 |

|* 2 | TABLE ACCESS FULL| VEHICLE | 1 | 220K| 214K|

-----------------------------------------------------------------

116

"ok"

117117

118118

but just maybe ....

119119

... someone already is

SQL> create table EMP as

2 select rownum empno,

3 mod(rownum,10) jobid,

4 mod(rownum,10)*1000 salary,

5 mod(rownum,50)+1 deptno

6 from dual

7 connect by rownum < 100000;

SQL> create table DEPT as

2 select rownum deptno,

3 'dept'||rownum dname

4 from dual

5 connect by rownum <= 100;

120

100,000 rows

100 rows

SQL> exec dbms_stats.gather_table_stats(user,'EMP');

SQL> exec dbms_stats.gather_table_stats(user,'DEPT');

SQL> create index EMP_IX on EMP ( deptno );

SQL> create index DEPT_IX on DEPT ( deptno );

121

SQL> select e.empno, d.dname

2 from emp e, dept d

3 where d.deptno = e.deptno

4 and e.jobid = 1

5 and e.salary > 5000;

no rows selected

----------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes |

----------------------------------------------------------------

| 0 | SELECT STATEMENT | | | |

| 1 | MERGE JOIN | | 4444 | 104K |

| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 100 | 1000 |

| 3 | INDEX FULL SCAN | DEPT_IX | 100 | |

|* 4 | SORT JOIN | | 4444 | 62216 |

|* 5 | TABLE ACCESS FULL | EMP | 4444 | 62216 |

----------------------------------------------------------------

122

4 and e.jobid = 1

5 and e.salary > 5000;

hard to

optimize

re-run the query

123

124

no anythingchanges to

SQL> select e.empno, d.dname

2 from emp e, dept d

3 where d.deptno = e.deptno

4 and e.jobid = 1

5 and e.salary > 5000;

no rows selected

---------------------------------------------------

| Id | Operation | Name | Rows | Bytes |

---------------------------------------------------

| 0 | SELECT STATEMENT | | | |

|* 1 | HASH JOIN | | 89 | 2136 |

| 2 | TABLE ACCESS FULL| DEPT | 1 | 10 |

|* 3 | TABLE ACCESS FULL| EMP | 4444 | 62216 |

---------------------------------------------------

125

11.2

126

the optimizer knows what "hard" is

127

cardinality feedback loop

128

its not continuous learning

129

several restrictions

130

SQL tuning advisor fallback

131

132

Feature:

result cache

133

134

SQL> create table MY_TMP as

2 select ....

Table created.

SQL> select ...

2 from ...

3 where COL in ( select COL from MY_TMP )

4 and ...

135

cache the results of queries

136

hard...

GTT,

plsql table,

materialised view

single session,

expiry issues,

staleness

137

SQL> SELECT name, value

2 FROM v$parameter

3 WHERE name LIKE 'result_cache%';

NAME VALUE

------------------------------ -----------

result_cache_mode MANUAL

result_cache_max_size 1081344

result_cache_max_result 5

result_cache_remote_expiration 0

memory

%

138

SQL> set autotrace traceonly stat

SQL> set timing on

SQL> select owner, count(*)

2 from T

3 group by owner

4 /

29 rows selected.

Elapsed: 00:00:03.98

Statistics

-----------------------------------------------------

0 recursive calls

1 db block gets

32192 consistent gets

32184 physical reads

96 redo size

[snip]

139

SQL> /

29 rows selected.

Elapsed: 00:00:03.80

Statistics

-----------------------------------------------------

0 recursive calls

1 db block gets

32192 consistent gets

32184 physical reads

96 redo size

[snip]

140

SQL> set autotrace traceonly stat

SQL> set timing on

SQL> select /*+ RESULT_CACHE */ owner, count(*)

2 from T

3 group by owner

4 /

29 rows selected.

Elapsed: 00:00:03.80

Statistics

-----------------------------------------------------

0 recursive calls

1 db block gets

32192 consistent gets

32184 physical reads

96 redo size

[snip]

141

SQL> set autotrace traceonly stat

SQL> set timing on

SQL> select /*+ RESULT_CACHE */ owner, count(*)

2 from T

3 group by owner

4 /

29 rows selected.

Elapsed: 00:00:00.04 !!!!!!!!!!!!

Statistics

-----------------------------------------------------

0 recursive calls

0 db block gets

0 consistent gets

0 physical reads

0 redo size

[snip]

142

cross session

143

SQL> select /*+ RESULT_CACHE */ owner, count(*)

2 from T

3 group by owner

4 /

29 rows selected.

Elapsed: 00:00:00.04

SQL> select /*+ RESULT_CACHE */ owner, count(*)

2 from T

3 group by owner

4 /

29 rows selected.

Elapsed: 00:00:03.80

session 2

session 1

144

automatic expiry

145

SQL> set timing on

SQL> select /*+ RESULT_CACHE */ owner, count(*)

2 from T

3 group by owner

4 /

29 rows selected.

Elapsed: 00:00:00.05

SQL> delete from T where rownum = 1;

1 row deleted.

SQL> select /*+ RESULT_CACHE */ owner, count(*)

2 from T

3 group by owner

4 /

Elapsed: 00:00:03.91

active txn

146

SQL> commit;

Commit complete.

SQL> select /*+ RESULT_CACHE */ owner, count(*)

2 from T

3 group by owner

4 /

Elapsed: 00:00:03.91

SQL> select /*+ RESULT_CACHE */ owner, count(*)

2 from T

3 group by owner

4 /

Elapsed: 00:00:00.04

reinstantiate cache

voila!

147

11.2

148

part of table definition

149

alter table T result_cache (mode force);

150

dependencies

151

v$result_cache_objects

v$result_cache_dependency

152

SQL> select

2 r.name,

3 listagg(o.name,' ') within group ( order by o.name ) as obj

4 from v$result_cache_objects r,

5 v$result_cache_dependency d,

6 sys.obj$ o

7 where r.type = 'Result'

8 and r.id =d.result_id

9 and d.object_no=o.obj#

10 group by r.name;

NAME OBJ

------------------------------------------------ ----------------

select /*+ RESULT_CACHE */ owner, count(*) T

from T

group by owner

select /*+ RESULT_CACHE */ owner, count(*) T1 T

from T, T1

group by owner

153

plsql too

154

SQL> desc COUNTRY_SALES

Name Null? Type

----------------- -------- ------------

CTRY NOT NULL VARCHAR2(10)

CRNCY NOT NULL VARCHAR2(3)

AMOUNT NUMBER

PRODUCT VARCHAR2(20)

TXN_DATE DATE

QUANTITY NUMBER(3)

"summarise the sales in $AUD"

155

currency conversion function

156

SOA

slower... obscure...

...awfully complicated

157

SQL> create or replace

2 function CURRENCY_CONVERT(code varchar2) return number is

3 l_service sys.utl_dbws.service;

4 l_call sys.utl_dbws.call;

5 l_result sys.anydata;

6

7 l_wsdl varchar2(100);

8 l_ns varchar2(100);

[snip]

15 begin

16 l_ns := 'http://www.webservicex.net/currencyconvertor.asmx';

17 l_wsdl := 'http://www.webservicex.net/currencyconvertor.asmx?wsdl';

[snip]

28

29 l_result := SYS.UTL_DBWS.INVOKE (

30 call_handle => l_call,

31 input_params => l_input_params);

[snip]

46 return sys.anydata.accessnumber(l_result);

47 end;

48 /

Function created.

158

SQL> select sum(CURRENCY_CONVERT(crncy)*amount) tot

2 from COUNTRY_SALES

3 /

TOT

----------

4799.62

Elapsed: 00:00:45.36

159

160

SQL> create or replace

2 function CURRENCY_CONVERT(code varchar2) return number RESULT_CACHE is

3 l_service sys.utl_dbws.service;

4 l_call sys.utl_dbws.call;

5 l_result sys.anydata;

6

7 l_wsdl varchar2(100);

8 l_ns varchar2(100);

[snip]

15 begin

16 l_ns := 'http://www.webservicex.net/currencyconvertor.asmx';

17 l_wsdl := 'http://www.webservicex.net/currencyconvertor.asmx?wsdl';

[snip]

28

29 l_result := SYS.UTL_DBWS.invoke (

30 call_handle => l_call,

31 input_params => l_input_params);

[snip]

46 return sys.anydata.accessnumber(l_result);

47 end;

48 /

Function created.

161

SQL> select sum(CURRENCY_CONVERT(crncy)*amount) tot

2 from COUNTRY_SALES

3 where rownum < 100

4 /

TOT

----------

4799.62

Elapsed: 00:00:15.78

SQL> /

TOT

----------

4799.62

Elapsed: 00:00:00.02

inter-row

cache benefit

all values

cached

162

explain plan

163

SQL> select /*+ RESULT_CACHE */ owner, max(object_id)

2 from T

3 group by owner

4 /

--------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes |

--------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 19 | 171 |

| 1 | RESULT CACHE | b82qdu5m139yr3fbna1x5r6g2d | | |

| 2 | HASH GROUP BY | | 19 | 171 |

| 3 | TABLE ACCESS FULL| T | 2201K| 18M |

--------------------------------------------------------------------------

indeterminate

164

SQL> select status

2 from v$result_cache_objects

3 where cache_id = 'b82qdu5m139yr3fbna1x5r6g2d';

STATUS

---------

Published

New - Result is still under construction

Published - Result is available for use

Bypass - Result will be bypassed from use

Expired - Result has exceeded expiration time

Invalid - Result is no longer available for use

?

165

two people, same query

select /*+ RESULT_CACHE */ …

select /*+ RESULT_CACHE */ …

166

when in doubt...

...try to break it

167

168

169

170

SQL> create or replace

2 function SLOW(n number) return number

3 deterministic is

4 begin

5 dbms_lock.sleep(1);

6 return n;

7 end;

8 /

Function created.

171

SQL> select /*+ RESULT_CACHE */ owner, slow(object_id)

2 from T

3 where rownum <= 120;

Elapsed: 00:02:01.13

--------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes |

--------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 119 | 1071 |

| 1 | RESULT CACHE | 14tnr7dxmvkp3244d69tw72z4p | | |

|* 2 | COUNT STOPKEY | | | |

| 3 | TABLE ACCESS FULL| T | 119 | 1071 |

--------------------------------------------------------------------------

172

SQL> select /*+ RESULT_CACHE */ owner, slow(object_id)

2 from T

3 where rownum < 120;

[5 seconds later...]

OWNER SLOW(OBJECT_ID)

------------------------------ ---------------

SYS 20

SYS 46

SYS 28

SYS 15

SYS 29

[still executing...]

SQL> select status

2 from v$result_cache_objects

3 where cache_id = '14tnr7dxmvkp3244d69tw72z4p';

STATUS

---------

New

session 2

SQL> select /*+ RESULT_CACHE */ owner, slow(object_id)

2 from T

3 where rownum < 120;

[executing...]

Elapsed: 00:03:03.54 !!!!!!!!!

173

SQL> select sid,

2 decode(lockwait,null,status,'BLOCKED') status

3 from v$session

4 where username = 'CONNOR';

SID STATUS

---------- --------

131 ACTIVE

143 BLOCKED

uh oh....

174

PARSING IN CURSOR #5 len=82 dep=0 uid=88 oct=3 lid=88

select /*+ RESULT_CACHE */ owner, slow(data_object_id)

from T

where rownum < 120

END OF STMT

PARSE #5:c=15625,e=28756,p=0,cr=0,cu=0,mis=1,r=0,tim=202781578

EXEC #5:c=0,e=60,p=0,cr=0,cu=0,mis=0,r=0,tim=202781659

WAIT #5: nam='enq: RC - Result Cache: Contention' ela= 10005714

WAIT #5: nam='enq: RC - Result Cache: Contention' ela= 10002485

WAIT #5: nam='enq: RC - Result Cache: Contention' ela= 10002804

WAIT #5: nam='enq: RC - Result Cache: Contention' ela= 10002549

WAIT #5: nam='enq: RC - Result Cache: Contention' ela= 10005258

WAIT #5: nam='enq: RC - Result Cache: Contention' ela= 10002461

WAIT #5: nam='direct path read' ela= 13770 file number=4 ...

WAIT #5: nam='direct path read' ela= 25 file number=4 ...

[etc]

175

better in 11.2

176

PARSING IN CURSOR #5 len=82 dep=0 uid=88 oct=3 lid=88

select /*+ RESULT_CACHE */ owner, slow(data_object_id)

from T

where rownum < 120

END OF STMT

PARSE #5:c=15625,e=28756,p=0,cr=0,cu=0,mis=1,r=0,tim=202781578

EXEC #5:c=0,e=60,p=0,cr=0,cu=0,mis=0,r=0,tim=202781659

WAIT #5: nam='enq: RC - Result Cache: Contention' ela= 10005714

WAIT #5: nam='direct path read' ela= 13770 file number=4 ...

WAIT #5: nam='direct path read' ela= 25 file number=4 ...

...

177

"take care....."

178

179

not too short....

why bother with result cache?

180

not too long....

might lock other people out

181

Feature:

compound triggers

182

example: table audit

183

SQL> desc T

Name Null? Type

----------------------------- -------- -------------

OWNER NOT NULL VARCHAR2(30)

OBJECT_NAME NOT NULL VARCHAR2(30)

SQL> desc T_AUDIT

Name Null? Type

----------------------------- -------- --------------

AUDIT_DATE DATE

AUDIT_ACTION CHAR(1)

OWNER NOT NULL VARCHAR2(30)

OBJECT_NAME NOT NULL VARCHAR2(30)

184

SQL> create or replace

2 trigger AUDIT_TRG

3 after insert or update or delete on T

4 for each row

5 declare

6 v_action varchar2(1) := case when updating then 'U'

7 when deleting then 'D' else 'I' end;

8 begin

9 if updating or inserting then

10 insert into T_AUDIT

11 values (sysdate

12 ,v_action

13 ,:new.owner

14 ,:new.object_name);

15 else

16 insert into T_AUDIT

17 values (sysdate

18 ,v_action

19 ,:old.owner

20 ,:old.object_name);

21 end if;

22 end;

23 /

Trigger created.

185

works but slow...

186

SQL> insert into T

2 select owner, object_name

3 from all_objects

4 where rownum <= 10000;

10000 rows created.

insert into T

select owner, object_name

from all_objects

where rownum <= 10000

call count cpu elapsed disk query current rows

------- ------ ------- ---------- -------- --------- ---------- ----------

Parse 1 0.01 0.00 0 0 0 0

Execute 1 3.10 3.05 88 123 10642 10000

Fetch 0 0.00 0.00 0 0 0 0

------- ------ ------- ---------- -------- --------- ---------- ----------

total 2 3.12 3.06 88 123 10642 10000

INSERT INTO T_AUDIT

VALUES (SYSDATE ,:B3 ,:B1 ,:B2 )

call count cpu elapsed disk query current rows

------- ------ ------- ---------- -------- --------- ---------- ----------

Parse 1 0.00 0.00 0 0 0 0

Execute 10000 0.79 0.97 2 109 10845 10000

Fetch 0 0.00 0.00 0 0 0 0

------- ------ ------- ---------- -------- --------- ---------- ----------

total 10001 0.79 0.97 2 109 10845 10000

187

bulk binding

"hard"

188

create or replace

package T_PKG is

type each_row is record ( action varchar2(1),

owner varchar2(30),

object_name varchar2(30)

);

type row_list is table of each_row

index by pls_integer;

g row_list;

end;

/

189

create or replace

trigger AUDIT_TRG1

before insert or update or delete on T

begin

t_pkg.g.delete;

end;

/

190

create or replace

trigger AUDIT_TRG2

after insert or update or delete on T

for each row

begin

if updating or inserting then

t_pkg.g(t_pkg.g.count+1).owner := :new.owner;

t_pkg.g(t_pkg.g.count).object_name := :new.object_name;

else

t_pkg.g(t_pkg.g.count).owner := :old.owner;

t_pkg.g(t_pkg.g.count).object_name := :old.object_name;

end if;

end;

/

191

create or replace

trigger AUDIT_TRG3

after insert or update or delete on T

declare

v_action varchar2(1) :=

case when updating then 'U'

when deleting then 'D'

else 'I' end;

begin

forall i in 1 .. t_pkg.g.count

insert into T_AUDIT

values (

sysdate,

v_action,

t_pkg.g(i).owner,

t_pkg.g(i).object_name);

t_pkg.g.delete;

end;

/

192

SQL> insert into T

2 select owner, object_name

3 from all_objects

4 where rownum <= 10000;

10000 rows created.

insert into T

select owner, object_name

from all_objects

where rownum <= 10000

call count cpu elapsed disk query current rows

------- ------ ------- --------- -------- ---------- ---------- ----------

Parse 1 0.00 0.00 0 33 0 0

Execute 1 0.56 0.58 0 91 10653 10000

Fetch 0 0.00 0.00 0 0 0 0

------- ------ ------- --------- -------- ---------- ---------- ----------

total 2 0.56 0.59 0 124 10653 10000

INSERT INTO T_AUDIT

VALUES

( SYSDATE, :B1 , :B2 , :B3 )

call count cpu elapsed disk query current rows

------- ------ ------- --------- -------- ---------- ---------- ----------

Parse 1 0.00 0.00 0 0 0 0

Execute 1 0.04 0.03 0 90 478 10000

Fetch 0 0.00 0.00 0 0 0 0

------- ------ ------- --------- -------- ---------- ---------- ----------

total 2 0.04 0.03 0 90 478 10000

193

no one did it ....

three triggers

additional package

194

11g compound triggers

195

create or replace

trigger AUDIT_TRG for insert or update or delete on T

compound trigger

before statement is

begin

...

end before statement;

after each row is

begin

...

end after each row;

after statement is

begin

...

end after statement;

end;

/

196

SQL> create or replace

2 trigger AUDIT_TRG for insert or update or delete on T compound trigger

3

4 type each_row is record ( action varchar2(1),5 owner varchar2(30),

6 object_name varchar2(30));7 type row_list is table of each_row index by pls_integer;

8 g row_list;

9 v_action varchar2(1) :=10 case when updating then 'U' when deleting then 'D' else 'I' end;

1112 before statement is

13 begin

14 g.delete;15 end before statement;

1617 after each row is

18 begin

1920 if updating or inserting then

21 g(g.count+1).owner := :new.owner;22 g(g.count).object_name := :new.object_name;

23 else

24 g(g.count).owner := :old.owner;

25 g(g.count).object_name := :old.object_name;

26 end if;

27 end after each row;

28

29 after statement is30 begin

31 forall i in 1 .. g.count32 insert into T_AUDIT

33 values (sysdate,v_action,g(i).owner,g(i).object_name);

34 g.delete;35 end after statement;

3637 end;

38 /

Trigger created.

197

one more thing on triggers...

198

the 107 slides you didn't see

199

SQL> create or replace

2 trigger AUDIT_TRG

3 after insert or update or delete on T

4 for each row

5 declare

6 v_action varchar2(1) :=

7 case when updating then 'U'

8 when deleting then 'D' else 'I' end case;

9 begin

10 if updating or inserting then

11 insert into T_AUDIT

12 values(sysdate,v_action,:new.owner,:new.object_name);

13 else

14 insert into T_AUDIT

15 values(sysdate,v_action,:old.owner,:old.object_name);

16 end if;

17 end;

18 /

Warning: Trigger created with compilation errors.

SQL> sho err

Errors for TRIGGER AUDIT_TRG:

LINE/COL ERROR

-------- -----------------------------------------------------------------

4/46 PLS-00103: Encountered the symbol "CASE" when expecting one of

the following:

* & = - + ; < / > at in is mod remainder not rem

<an exponent (**)> <> or != or ~= >= <= <> and or like like2

200

SQL> create or replace

2 trigger AUDIT_TRG

3 after insert or update or delete on T

4 for each row

5 declare

6 v_action varchar2(1) :=

7 case when updating then 'U'

8 when deleting then 'D' else 'I' end;

9 begin

10 if updateing or inserting then

11 insert into T_AUDIT

12 values(sysdate,v_action,:new.owner,:new.object_name);

13 else

14 insert into T_AUDIT

15 values(sysdate,v_action,:old.owner,:old.object_name);

16 end if;

17 end;

18 /

Warning: Trigger created with compilation errors.

SQL> sho err

Errors for TRIGGER AUDIT_TRG:

LINE/COL ERROR

-------- -----------------------------------------------------------------

6/3 PL/SQL: Statement ignored

6/6 PLS-00201: identifier 'UPDATEING' must be declared

201

SQL> create or replace

2 trigger AUDIT_TRG

3 after insert or update or delete on T

4 for each row

5 declare

6 v_action varchar2(1) :=

7 case when updating then 'U'

8 when deleting then 'D' else 'I' end;

9 begin

10 if updating or inserting then

11 insert into TAUDIT

12 values(sysdate,v_action,:new.owner,:new.object_name);

13 else

14 insert into T_AUDIT

15 values(sysdate,v_action,:old.owner,:old.object_name);

16 end if;

17 end;

18 /

Warning: Trigger created with compilation errors.

SQL> sho err

Errors for TRIGGER AUDIT_TRG:

LINE/COL ERROR

-------- ------------------------------------------------------

7/6 PL/SQL: SQL Statement ignored

7/18 PL/SQL: ORA-00942: table or view does not exist

202

SQL> create or replace

2 trigger AUDIT_TRG

3 after insert or update or delete on T

4 for each row

5 declare

6 v_action varchar2(1) :=

7 case when updating then 'U'

8 when deleting then 'D' else 'I' end;

9 begin

10 if updating or inserting then

11 insert into T_AUDIT

12 values(sysdate,v_action,:new.owner,new.object_name);

13 else

14 insert into T_AUDIT

15 values(sysdate,v_action,:old.owner,:old.object_name);

16 end if;

17 end;

18 /

Warning: Trigger created with compilation errors.

SQL> sho err

Errors for TRIGGER AUDIT_TRG:

LINE/COL ERROR

-------- ---------------------------------------------------------

10/6 PL/SQL: SQL Statement ignored

11/45 PL/SQL: ORA-00984: column not allowed here

203

etc etc etc

204

Which of the following is the largest ?

205

T

206

SQL> insert into T values ('X','Y');

insert into T values ('X','Y')

*

ERROR at line 1:

ORA-04098: trigger 'CONNOR.AUDIT_TRG' is

invalid and failed re-validation

207

Feature:

11g disabled triggers

208

SQL> create or replace

2 trigger AUDIT_TRG

3 after insert or update or delete on T

4 for each row

5 DISABLE

6 declare

7 v_action varchar2(1) :=

8 case when updating then 'U'

9 when deleting then 'D' else 'I' end;

10 begin

11 if updating or inserting then

12 insert into T_AUDIT

13 values(sysdate,v_action,:new.owner,:new.object_name);

14 else

15 insert into T_AUDIT

16 values(sysdate,v_action,:old.owner,old.object_name);

17 end if;

18 end;

19 /

Warning: Trigger created with compilation errors.

209

SQL> select status from user_triggers

2 where trigger_name = 'AUDIT_TRG';

STATUS

--------

DISABLED

SQL> insert into T values ('X','Y');

1 row created.

210

Feature:

bulk bind just got better

211

SQL> declare

2 type row_list is table of all_objects%rowtype

3 index by pls_integer;

4 g row_list;

5 begin

6 for i in ( select * from all_objects

7 where rownum < 10 ) loop

8 g(g.count+1) := i;

9 end loop;

14 end;

15 /

10

11 forall i in 1 .. g.count

12 insert into T_COMP

13 values ( g(i).owner, g(i).object_name );

values ( g(i).owner, g(i).object_name );

*

ERROR at line 13:

ORA-06550: line 13, column 15:

PLS-00436: implementation restriction: cannot reference

fields of BULK In-BIND table of records

ORA-06550: line 13, column 15:

PLS-00382: expression is of wrong type

ORA-06550: line 13, column 27:

212

11g

213

SQL> declare

2 type row_list is table of all_objects%rowtype

3 index by pls_integer;

4 g row_list;

5 begin

6 for i in ( select * from all_objects

7 where rownum < 10 ) loop

8 g(g.count+1) := i;

9 end loop;

10

11 forall i in 1 .. g.count

12 insert into T

13 values ( g(i).owner, g(i).object_name );

14 end;

15 /

PL/SQL procedure successfully completed.

214

danger:

gratuitous book plug

215

216

Feature:

Dependency tracking

217

10g and below

218

SQL> create table T ( x number, y number );

Table created.

SQL> create or replace

2 view MY_VIEW as

3 select x,y from T;

View created.

219

SQL> alter table T add Z number;

Table altered.

SQL> select status

2 from user_objects

3 where object_name = 'MY_VIEW';

STATUS

-------

INVALID

220

11g

221

SQL> alter table T add Z number;

Table altered.

SQL> select status

2 from user_objects

3 where object_name = 'MY_VIEW';

STATUS

-------

VALID

222

plsql too

223

quick review

224

"always use packages"

225

ALL production code !

226

more secure

227

228

break the invalidation chain

229

proc A proc B proc C proc D

pack A pack B pack C pack D

body A body B body C body D

230

11g

231

change the spec as well !

232

pack A pack B pack C pack D

body A body B body C body D

233

SQL> create or replace

2 package PKG is

3 procedure P1;

4 end;

5 /

Package created.

SQL> create or replace

2 package body PKG is

3 procedure P1 is

4 x number;

5 begin

6 x := 1;

7 end;

8 end;

9 /

Package body created.

SQL> create or replace

2 procedure PRC is

3 begin

4 pkg.p1;

5 end;

6 /

Procedure created.

234

SQL> create or replace

2 package PKG is

3 procedure P1;

4 procedure P2;

5 end;

6 /

Package created.

SQL> create or replace

2 package body PKG is

3 procedure P1 is

4 x number;

5 begin

6 x := 1;

7 end;

8

9 procedure p2 is

10 x number;

11 begin

12 x := myseq.nextval;

13 end;

14 end;

15 /

Package body created.

235

SQL> select status

2 from user_objects

3 where object_name = 'PRC';

STATUS

-------

INVALID

SQL> select status

2 from user_objects

3 where object_name = 'PRC';

STATUS

-------

VALID

10g and below

11g

236

package D

237

the order is important

238

SQL> create or replace

2 package PKG is

3 procedure p1;

4 end;

5 /

Package created.

SQL> create or replace

2 package body PKG is

3 procedure p1 is

4 x number;

5 begin

6 x := 1;

7 end;

8

9 end;

10 /

Package body created.

239

SQL> create or replace

2 package PKG is

3 procedure p2;

4 procedure p1;

5 end;

6 /

Package created.

SQL> create or replace

2 package body PKG is

3 procedure p2 is

4 x number;

5 begin

6 x := myseq.nextval;

7 end;

8

9 procedure p1 is

10 x number;

11 begin

12 x := 1;

13 end;

14

15 end;

16 /

Package body created.

240

moral of the story

241

change package bodies

(as before)

242

add to bottom of specs

243

this is NOT about state

244

SQL> create or replace

2 package PKG is

3 procedure p1;

4 end;

5 /

Package created.

SQL> create or replace

2 package body PKG is

3

4 my_global_var date;

5

6 procedure p1 is

7 x number;

8 begin

9 if my_global_var is null then

10 my_global_var := sysdate;

11 end if;

12 end;

13 end;

14 /

Package body created.

245

SQL> create or replace

2 procedure PRC is

3 begin

4 pkg.p1;

5 end;

6 /

Procedure created.

SQL> exec PRC;

SQL> create or replace

2 package body PKG is

3

4 my_global_var date;

5

6 procedure p1 is

7 x number;

8 begin

9 if my_global_var is null then

10 my_global_var := sysdate;

11 end if;

12 end;

13 end;

14 /

Package body created.

SQL> exec PRC;

BEGIN PRC; END;

*

ERROR at line 1:

ORA-04068: existing state of packages has been discarded

ORA-04061: existing state of package body "PKG" has been invalidated

ORA-04065: not executed, altered or dropped package body "PKG"

ORA-06508: PL/SQL: could not find program unit being called: "PKG"

ORA-06512: at "PRC", line 3

ORA-06512: at line 1

246

keep stateful data separate

minimise global variables

store types separately

247

you may have noticed...

248

SQL> create or replace

2 package body PKG is

3 procedure p2 is

4 x number;

5 begin

6 x := myseq.nextval;

7 end;

8

9 procedure p1 is

10 x number;

11 begin

12 x := 1;

13 end;

14

15 end;

16 /

Package body created.

249

Direct sequence access

250

251

can we reduce the risk further ?

253

SQL> create or replace

2 procedure THE_SINGLE_MOST_IMPORTANT_PROC_IN_MY_APP is

begin

....

254

11.2

255

256

"version control"

257

package PKG is

select COL1, COL2

from MY_VIEW

package PKG(V2) is

select COL1, NEW_COL

from MY_VIEW(V2)

both in active use !

258

editions

259

SQL> desc DBA_EDITIONS

Name Null? Type

----------------------------- -------- -------------

EDITION_NAME NOT NULL VARCHAR2(30)

PARENT_EDITION_NAME VARCHAR2(30)

USABLE VARCHAR2(3)

260

SQL> select *

2 from DBA_EDITIONS;

EDITION_NAME PARENT_EDITION USABLE

------------ -------------- ------

ORA$BASE YES

261

PKG1 PKG2 PKG3 PKG4 PKG5PKG2 PKG4

PKG1 PKG3 PKG5

ora$base

version2

262

no space =

probably editionable

263

indexes

264

Invisible indexes

265

tables

266

views

267

SQL> desc MY_TABLE

Name Null? Type

----------------------------- -------- -----------------

V1_COL1 NUMBER

V1_COL2 DATE

V1_COL3 VARCHAR2(10)

V1_ONLY_COL4 VARCHAR2(10)

V2_NEWCOL5 DATE

V2_NEWCOL6 NUMBER

version1

version2

create view V_MY_TABLE as

select V1_COL1 as col1,

V1_COL2 as col2,

V1_COL3 as col3,

V1_ONLY_COL4 as col4,

from MY_TABLE

create view V_MY_TABLE as

select V1_COL1 as col1,

V1_COL2 as col2,

V1_COL3 as col3,

V2_NEWCOL5 as col5,

V2_NEWCOL6 as col6

from MY_TABLE

268

(special) viewseditioning

269

basic example

270

SQL> desc EMP

Name Null? Type

----------------------------- -------- -------------

EMPNO NOT NULL NUMBER(4)

ENAME VARCHAR2(10)

JOB VARCHAR2(9)

MGR NUMBER(4)

HIREDATE DATE

SAL NUMBER(7,2)

COMM NUMBER(7,2)

DEPTNO NUMBER(2)

271

SQL> create or replace

2 package body EMP_MAINT is

3 procedure hire_emp(p_empno emp.empno%type,

4 p_ename emp.ename%type,

5 p_job emp.job%type,

6 p_sal emp.sal%type,

7 p_deptno emp.deptno%type) is

8 begin

9 insert into EMP

10 (empno,ename,job,sal,deptno)

11 values

12 (p_empno,p_ename,p_job,p_sal,p_deptno);

13 end;

14 end;

15 /

Package body created.

272

version 2

273

SQL> desc EMP

Name Null? Type

----------------------------- -------- -------------

EMPNO NOT NULL NUMBER(4)

ENAME VARCHAR2(10)

JOB VARCHAR2(9)

MGR NUMBER(4)

HIREDATE DATE

SAL NUMBER(7,2)

COMM NUMBER(7,2)

DEPTNO NUMBER(2)

ETYPE VARCHAR2(10)

TERMINATION_DATE DATE

Contract/Permanent

End of Contract

274

old style

275

SQL> alter table EMP add ETYPE VARCHAR2(1);

Table altered.

SQL> alter table EMP add TERMINATION_DATE DATE;

Table altered.

SQL> update EMP set ETYPE = 'Permanent';

14 rows updated.

SQL> alter table EMP modify ETYPE not null;

Table altered.

SQL> alter table EMP add constraint

2 EMP_CHK01 check ( ETYPE in ('Contract',

'Permanent'));

Table altered.

276

broken application

277

SQL> exec EMP_MAINT.HIRE_EMP(1,'Sue','SALES',10,10)

BEGIN EMP_MAINT.HIRE_EMP(1,'Sue','SALES',10,10); END;

*

ERROR at line 1:

ORA-01400: cannot insert NULL into ("SCOTT"."EMP"."ETYPE")

ORA-06512: at "SCOTT.EMP_MAINT", line 8

ORA-06512: at line 1

278

outage

279

SQL> create or replace

2 package body EMP_MAINT is

3 procedure hire_emp(p_empno emp.empno%type,

4 p_ename emp.ename%type,

5 p_job emp.job%type,

6 p_sal emp.sal%type,

7 p_deptno emp.deptno%type,

8 p_etype emp.etype%type,

9 p_term emp.termination_date%type) is

10 begin

11 insert into EMP

12 (empno,ename,job,sal,deptno,etype,termination_date)

13 values

14 (p_empno,p_ename,p_job,p_sal,p_deptno,p_etype,p_term);

15 end;

16 end;

17 /

Package body created.

280

now with editions

281

step 1

282

enable editions

283

SQL> alter user SCOTT enable editions;

User altered.

284

this is a big deal

285

Enabling editions is retroactive and irreversible.

- 11g2 doc

286

Every editionable-type object that

the user has owned or will own

is an editioned object.

287

step 2

288

abstract your tables

289

SQL> alter table EMP rename to "_EMP";

Table altered.

SQL> create or replace

2 editioning view EMP as

3 select * from "_EMP";

View created.

SQL> exec dbms_utility.compile_schema(user)

PL/SQL procedure successfully completed.

290

obtuse

_EMP

291

SQL> select * from _EMP;

select * from _EMP

*

ERROR at line 1:

ORA-00911: invalid character

292

may mean an outage

293

SQL> alter table "_EMP" add ETYPE VARCHAR2(1);

Table altered.

SQL> alter table "_EMP" add TERMINATION_DATE DATE;

Table altered.

SQL> alter table "_EMP" add constraint

2 EMP_CHK01 check ( ETYPE in ('Contract',

'Permanent'));

Table altered.

SQL> alter table "_EMP" modify ETYPE not null;

Table altered.

294

create an edition

295

SQL> create edition "APP_V2"

as child of ORA$BASE2 /

Edition created.

296

SQL> conn SCOTT/TIGER

Connected.

SQL> alter session set edition = APP_V2;

ERROR:

ORA-38802: edition does not exist

297

SQL> grant USE on edition APP_V2 to SCOTT;

Grant succeeded.

298

SQL> alter session set edition = APP_V2;

SQL> create or replace

2 editioning view EMP as

3 select * from "_EMP"

4 /

View created.

299

SQL> alter session set edition = ORA$BASE;

Session altered.

SQL> desc EMP

Name Null? Type

----------------------------- -------- ----------------

EMPNO NOT NULL NUMBER(4)

ENAME VARCHAR2(10)

JOB VARCHAR2(9)

MGR NUMBER(4)

HIREDATE DATE

SAL NUMBER(7,2)

COMM NUMBER(7,2)

DEPTNO NUMBER(2)

300

SQL> alter session set edition = APP_V2;

Session altered.

SQL> desc EMP

Name Null? Type

----------------------------- -------- ---------------

EMPNO NOT NULL NUMBER(4)

ENAME VARCHAR2(10)

JOB VARCHAR2(9)

MGR NUMBER(4)

HIREDATE DATE

SAL NUMBER(7,2)

COMM NUMBER(7,2)

DEPTNO NUMBER(2)

ETYPE VARCHAR2(10)

TERMINATION_DATE DATE

301

SQL> select sys_context('USERENV',

2 'CURRENT_EDITION_NAME') edt

3 from dual;

EDT

--------------

APP_V2

302

SQL> create or replace

2 package body EMP_MAINT is

3 procedure hire_emp(p_empno emp.empno%type,

4 p_ename emp.ename%type,

5 p_job emp.job%type,

6 p_sal emp.sal%type,

7 p_deptno emp.deptno%type,

8 p_etype emp.etype%type,

9 p_term emp.termination_date%type) is

10 begin

11 insert into EMP

12 (empno,ename,job,sal,deptno,etype,termination_date)

13 values

14 (p_empno,p_ename,p_job,p_sal,p_deptno,p_etype,p_term);

15 end;

16 end;

17 /

Package body created.

303

SQL> alter session set edition = ORA$BASE;

Session altered.

SQL> begin

2 EMP_MAINT.HIRE_EMP(

3 p_empno =>1,

4 p_ename =>'Sue',

5 p_job =>'SALES',

6 p_sal =>10,

7 p_deptno =>20);

8 end;

9 /

PL/SQL procedure successfully completed.

304

SQL> alter session set edition = APP_V2;

Session altered.

SQL> begin

2 EMP_MAINT.HIRE_EMP(

3 p_empno =>2,

4 p_ename =>'Mike',

5 p_job =>'SALES',

6 p_sal =>10,

7 p_deptno =>20,

8 p_etype =>'Contract'

9 p_term =>'10-JAN-2012');

10 end;

11 /

PL/SQL procedure successfully completed.

305

we're close....

306

ETYPE not null

307

SQL> alter session set edition = APP_V2;

Session altered.

SQL> begin

2 EMP_MAINT.HIRE_EMP(

3 p_empno =>2,

4 p_ename =>'Mike',

5 p_job =>'SALES',

6 p_sal =>10,

7 p_deptno =>20,

8 p_etype =>null

9 p_term =>'10-JAN-2012');

10 end;

11 /

PL/SQL procedure successfully completed.

308

constraints not (natively) editionable

309

SQL> alter table "_EMP" add constraint

2 EMP_CHK02 check (

3 SYS_CONTEXT('USERENV',

4 'CURRENT_EDITION_NAME')

5 = 'ORA$BASE'

6 OR ETYPE is not null

7 );

Table altered.

310

cross edition consistency

APP_V2

"everyone has an ETYPE"

APP_V1 (aka ORA$BASE)

"what is an ETYPE"

311

cross edition triggers

312

SQL> alter session set edition = APP_V2;

Session altered.

SQL> CREATE OR REPLACE TRIGGER emp_v1_to_v2

2 BEFORE INSERT OR UPDATE ON "_EMP"

3 FOR EACH ROW

4 FORWARD CROSSEDITION

5 DISABLE

6 BEGIN

7 :new.etype := nvl(:new.etype,'Permanent');

8 :new.termination_date := null;

9 END;

10 /

Trigger created.

313

SQL> CREATE OR REPLACE TRIGGER emp_v2_to_v1

2 BEFORE INSERT OR UPDATE ON "_EMP"

3 FOR EACH ROW

4 REVERSE CROSSEDITION

5 DISABLE

6 BEGIN

7 ...

8 ...

9 END;

10 /

Trigger created.

314

both in the new edition

"the working edition is sacred"

315

SQL> alter session set edition = APP_V2;

Session altered.

SQL> alter trigger EMP_V1_TO_V2 enable;

Trigger altered.

316

all new / modified data

317

historical data

uncommitted data

318

SQL> alter session set edition = ORA$BASE;

Session altered.

SQL> declare

2 ok boolean;

3 scn number;

4 begin

5 ok :=

6 dbms_utility.wait_on_pending_dml('"_EMP"',10, scn);

7

8 if ok then

9 update EMP set sal=sal;

10 end if;

11 end;

12 /

PL/SQL procedure successfully completed.

319

SQL> select empno, etype from "_EMP";

EMPNO ETYPE

---------- ----------

1 Contract

2 Contract

7369 Permanent

7499 Permanent

7521 Permanent

7566 Permanent

7654 Permanent

7698 Permanent

7782 Permanent

7788 Permanent

7839 Permanent

7844 Permanent

7876 Permanent

7900 Permanent

7902 Permanent

7934 Permanent

320

or DBMS_SQL

321

or DBMS_PARALLEL_EXECUTE

322

voila !

323

move people over

324

SQL> create or replace

2 trigger DEFAULT_EDITION

3 after logon on database

4 begin

5 execute immediate

6 'alter session set edition = APP_V2';

7 end;

8 /

325

SQL> create or replace

2 trigger DEFAULT_EDITION

3 after logon on database

4 begin

5 dbms_session.set_edition_deferred( 'APP_V2' );

7 end;

8 /

326

better in 11.2.0.2

use services

327

retire old edition

optional

328

how do I get started

329

first.... come clean

330

331

taking ... outagesstop ...

332

before

you

start

333

334

more complicated

than you think....

335

enabling editions

336

probably the whole database

337

cross user consistency

338

SQL> connect / as sysdba

Connected.

sys@db112> alter user TO_BE_EDITIONED enable editions;

alter user TO_BE_EDITIONED enable editions

*

ERROR at line 1:

ORA-38819: user TO_BE_EDITIONED owns one or more

objects whose type is editionable and that have

noneditioned dependent objects

339

select *

from DBA_DEPENDENCIES

where ( OWNER in ( SELECT username

from dba_users

where EDITIONS_ENABLED = 'N' )

OR TYPE NOT IN (

'VIEW','SYNONYM','PROCEDURE','FUNCTION'

,'PACKAGE','NON-EXISTENT','PACKAGE BODY'

,'TRIGGER','TYPE','TYPE BODY'

,'LIBRARY','ASSEMBLY')

)

and REFERENCED_OWNER = 'TO_BE_EDITIONED'

and TYPE IN (

'VIEW','SYNONYM','PROCEDURE','FUNCTION'

,'PACKAGE','NON-EXISTENT','PACKAGE BODY'

,'TRIGGER','TYPE','TYPE BODY'

,'LIBRARY','ASSEMBLY')

and REFERENCED_OWNER != OWNER

340

table = data store

for all versions...

341

online upgrade ...

342

... is not just editions

343

editions

ddl_timeout

invisible indexes

column naming

create index online

fallback

version control

constraints

344

existing processes / scripts

345

drop

346

rename

347

edition v1

edition v2

T1 T2

T2 T1

348

edition v1

edition v2

col1 NUMBER

col1 DATE

_v1

_v2

349

edition v1

edition v2

T1 (PK=col1,col2)

T1 (PK=col1,col3)

350

contexts

database links

queues

VPD

FGA

351

352

wrap up

353

lots of things not covered

354

11g / 11.2 very very nice

355

"Oracle 11g is the greatest

invention in the history of man"

- Anon, 2008

Connor McDonald

OracleDBA

co

.uk

357

358

ORA-00041

www.oracledba.co.uk

“active time limit exceeded - session terminated”