Connor McDonald 11g for developers

Post on 30-Jun-2015

1.935 views 3 download

description

11g for developers

Transcript of Connor McDonald 11g for developers

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

Connor McDonald

6

"why bother?"

7

2007 2008 2009 2010 2011 2012 2013 2014 2015

11g 11.1.0.7 11.2

management

visibility

11g

desupported

11.1.0.6

"why bother?"

(part 2)

9

don’t reinvent

12

there's a lot in 11g !

<apology>

</apology>

14

some cool things....

15

some not so cool things....

16

"11g is now production"

17

18

11g ≠

19

20

coolness barometer

21

first impressions

22

23

ORA-01017: invalid username/password; logon denied

24

ORA-28000: the account is locked

25

case sensitive passwords

26

default profile tightened

27

password complexity

28

be patient

29

30

snippets

31

snippets #1:

sqlplus BLOBS

32

10g and below

33

SQL> select PASSPORT_PHOTO

2 from PERSON

3 where surname = 'MCDONALD'

4 /

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

34

SQL> select PASSPORT_PHOTO

2 from PERSON

3 where surname = 'MCDONALD'

4 /

MUGSHOT_BLOB

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

D0CF11E0A1B11AE1000000000000000000000000000000003E000

02300000001000000FEFFFFFF0000000020000000

35

snippets #2:

sqlplus error logging

36

SQL> set errorlogging on

37

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

38

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

39

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

40

installation scripts

SQL> set errorlogging on

SQL> @create_all_objects

works on 10g too…

41

snippets #3:

sqlplus transaction safety

42

43

SQL> set exitcommit

44

snippets #4:

dbms_utility.get_sql_hash

45

SQL> select hash_value

2 from v$sql

3 where sql_text = 'SELECT 99 FROM DUAL';

HASH_VALUE

----------

835694897

46

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)

47

snippets #5:

listagg

classical problem

48

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

49

DEPTNO MEMBERS

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

10 CLARK,KING,MILLER

20 SMITH,JONES,SCOTT,ADAMS,FORD

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

50

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

51- 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

52- 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;

53- 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 /54- Tom Kyte

55

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

56

Feature:

real time sql monitoring

57

58

59

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

60

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)|

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

61

62

SQL> select

2 DBMS_SQLTUNE.REPORT_SQL_MONITOR(

3 sql_id=>'d3ncuxj7629bf',

4 report_level=>'ALL',

5 type=>'HTML') as report

6 from dual;

63

67

Feature:

statistics enhancements

67

68

69

70

cardinality is everything

70

71

same with Oracle

71

72

some real(ish) data

72

73

SQL> desc VEHICLE

Name Null? Type

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

ID NUMBER

MAKE VARCHAR2(6)

MODEL VARCHAR2(6)

SQL> select count(*)

2 from VEHICLE;

COUNT(*)

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

2,157,079

73

74

default stats not enough

74

75

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|

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

75

76

histogram

76

77

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.

77

78

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|

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

78

79

make AND model

79

80

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

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

80

81

three things

81

82

50% of Holdens are Commodores

82

83

8484

85

no correlation

10g and before

85

86

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

| Id | Operation | Rows | Bytes |

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

| 0 | SELECT STATEMENT | 1 | 14 |

| 1 | SORT AGGREGATE | 1 | 14 |

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

86

87

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)

87

88

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

88

89

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.

89

90

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|

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

90

9191

actual versus estimate

92

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|

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

92

93

its just another column

93

94

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

94

95

forget ...

95

96

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")

96

97

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

97

98

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

98

99

virtual column

99

100100

SYS_OP_COMBINED_HASH

101

hash means equality

101

102

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

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

102

103

can we solve this ?

103

104

two enhancements

104

105

adaptive cursor sharing

11.1

105

106

11.2

106

much

107

much

better

108

109109

recall

110110

cardinality

111111

actual versus estimate

112112

employ someone....

113

SQL> select

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|

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

113

"ok"

count(*)/*+ GATHER_PLAN_STATISTICS */

114114

115115

but just maybe ....

116116

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

117

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 );

118

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 |

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

119

4 and e.jobid = 1

5 and e.salary > 5000;

hard to

optimize

re-run the query

120

121

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 |

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

122

11.2

123

the optimizer knows what "hard" is

124

cardinality feedback loop

125

its not continuous learning

126

several restrictions

127

SQL tuning advisor fallback

128

129

Feature:

result cache

130

131

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

132

cache the results of queries

133

hard...

GTT, plsql table, ...

single session,

expiry issues...

134

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

%

135

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]

136

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]

137

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]

138

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]

139

cross session

140

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

141

automatic expiry

142

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

143

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!

144

11.2

145

part of table definition

146

alter table T result_cache (mode force);

147

dependencies

148

v$result_cache_objects

v$result_cache_dependency

149

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

150

plsql too

151

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"

152

currency conversion function

153

SOA

slower... obscure...

...awfully complicated

154

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.

155

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

2 from COUNTRY_SALES

3 /

TOT

----------

4799.62

Elapsed: 00:00:45.36

156

157

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.

158

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

159

explain plan

160

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

161

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

?

162

two people, same query

select /*+ RESULT_CACHE */ …

select /*+ RESULT_CACHE */ …

163

when in doubt...

...try to break it

164

165

166

167

SQL> create or replace

2 function SLOW(n number) return number

3 is

4 begin

5 dbms_lock.sleep(1);

6 return n;

7 end;

8 /

Function created.

168

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 |

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

169

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 !!!!!!!!!

170

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

171

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]

172

better in 11.2

173

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

...

174

"take care....."

175

176

not too short....

why bother with result cache?

177

not too long....

might lock other people out

178

Feature:

compound triggers

179

example: table audit

180

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)

181

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.

182

works but slow...

183

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

184

bulk binding

"hard"

185

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;

/

186

create or replace

trigger AUDIT_TRG1

before insert or update or delete on T

begin

t_pkg.g.delete;

end;

/

187

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;

/

188

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;

/

189

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

190

no one did it ....

three triggers

additional package

191

11g compound triggers

192

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;

/

193

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;

11

12 before statement is

13 begin

14 g.delete;

15 end before statement;

16

17 after each row is

18 begin

19

20 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 is

30 begin

31 forall i in 1 .. g.count

32 insert into T_AUDIT

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

34 g.delete;

35 end after statement;

36

37 end;

38 /

Trigger created.

194

one more thing on triggers...

195

the 107 slides you didn't see

196

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

197

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

198

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

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;

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

200

etc etc etc

201

Which of the following is the largest ?

202

T

203

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

204

Feature:

11g disabled triggers

205

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.

206

SQL> select status from user_triggers

2 where trigger_name = 'AUDIT_TRG';

STATUS

--------

DISABLED

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

1 row created.

207

Feature:

Dependency tracking

208

10g and below

209

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.

210

SQL> alter table T add Z number;

Table altered.

SQL> select status

2 from user_objects

3 where object_name = 'MY_VIEW';

STATUS

-------

INVALID

211

11g

212

better granularity

213

SQL> alter table T add Z number;

Table altered.

SQL> select status

2 from user_objects

3 where object_name = 'MY_VIEW';

STATUS

-------

VALID

214

plsql too

215

quick review

216

"always use packages"

217

ALL production code !

218

219

break the invalidation chain

220

proc A proc B proc C proc D

pack A pack B pack C pack D

body A body B body C body D

221

11g

222

change the spec as well !

223

pack A pack B pack C pack D

body A body B body C body D

224

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.

225

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.

226

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

227

package D

228

the order is important

229

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.

230

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.

231

moral of the story

232

change package bodies

(as before)

233

add to bottom of specs

234

this is NOT about package state

235

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.

236

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

237

keep stateful data separate

minimise global variables

store types separately

238

you may have noticed...

239

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

Direct sequence access

241

242

can we reduce the risk further ?

243

Feature:

editions

244

SQL> create or replace

2 procedure THE_SINGLE_MOST_IMPORTANT_PROC_IN_MY_APP is

begin

....

245

11.2

246

247

"version control"

248

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 !

249

SQL> desc DBA_EDITIONS

Name Null? Type

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

EDITION_NAME NOT NULL VARCHAR2(30)

PARENT_EDITION_NAME VARCHAR2(30)

USABLE VARCHAR2(3)

250

SQL> select *

2 from DBA_EDITIONS;

EDITION_NAME PARENT_EDITION USABLE

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

ORA$BASE YES

251

PKG1 PKG2 PKG3 PKG4 PKG5PKG2 PKG4

PKG1 PKG3 PKG5

ora$base

version2

252

no space =

probably editionable

253

indexes

254

Invisible indexes

255

tables

256

views

257

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

258

(special) viewseditioning

259

basic example

260

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)

261

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.

262

version 2

263

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

264

old style

265

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.

266

broken application

267

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

268

outage

269

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.

270

now with editions

271

step 1

272

enable editions

273

SQL> alter user SCOTT enable editions;

User altered.

274

this is a big deal

275

Enabling editions is retroactive and irreversible.

- 11g2 doc

276

step 2

277

abstract your tables

278

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.

279

obtuse

_EMP

280

SQL> select * from _EMP;

select * from _EMP

*

ERROR at line 1:

ORA-00911: invalid character

281

may mean an outage

as you upgrade to 11.2

282

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.

283

create an edition

284

SQL> create edition "APP_V2"

2 /

Edition created.

285

SQL> conn SCOTT/TIGER

Connected.

SQL> alter session set edition = APP_V2;

ERROR:

ORA-38802: edition does not exist

286

SQL> grant USE on edition APP_V2 to SCOTT;

Grant succeeded.

287

SQL> alter session set edition = APP_V2;

SQL> create or replace

2 editioning view EMP as

3 select * from "_EMP"

4 /

View created.

288

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)

289

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

290

SQL> select sys_context('USERENV',

2 'CURRENT_EDITION_NAME') edt

3 from dual;

EDT

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

APP_V2

291

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.

292

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.

293

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.

294

we're close....

295

ETYPE not null

296

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.

297

constraints not (natively) editionable

298

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.

299

cross edition consistency

APP_V2

"everyone has an ETYPE"

APP_V1 (aka ORA$BASE)

"what is an ETYPE"

300

cross edition triggers

301

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.

302

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.

303

both in the new edition

"the working edition is sacred"

304

SQL> alter session set edition = APP_V2;

Session altered.

SQL> alter trigger EMP_V1_TO_V2 enable;

Trigger altered.

305

all new / modified data

306

historical data

uncommitted data

307

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.

308

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

309

or DBMS_SQL

310

or DBMS_PARALLEL_EXECUTE

311

voila !

312

move people over

313

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 /

314

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 /

315

retire old edition

optional

316

how do I get started

317

first.... come clean

318

319

taking ... outagesstop ...

320

before

you

start

321

322

more complicated

than you think....

323

enabling editions

324

probably the whole database

325

cross user consistency

326

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

327

SQL> alter user TO_BE_EDITIONED enable editions FORCE;

User altered.

328

SQL> select owner, object_name, status

2 from dba_objects

3 where owner in (

4 'TO_BE_EDITIONED',

5 'NOT_EDITIONED');

OWNER OBJECT_NAME STATUS

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

TO_BE_EDITIONED EMP VALID

NOT_EDITIONED MY_EMPV INVALID

329

possibly not so "online"

330

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

331

PARSING IN CURSOR #3 len=487 dep=1 uid=0 oct=3 ...

select d.owner#,

u.name,

d.name,

d.namespace,

d.stime

from obj$ d,

dependency$ dep,

obj$ p,

user$ u

where d.obj# = dep.d_obj#

and p.obj# = dep.p_obj#

and d.remoteowner is null

and p.owner# = :1

and d.owner# = u.user#

and p.type# in (4,5,7,8,9,10,11,12,13,14,22,87)

and ((u.type# != 2 and bitand(u.spare1, 16) = 0

and u.user#!= p.owner#)

or (d.type# not in 4,5,7,8,9,10,11,12,13,14,22,87)))

332

PARSING IN CURSOR #3 len=487 dep=1 uid=0 oct=3 ...

select d.owner#,

u.name,

d.name,

d.namespace,

d.stime

from obj$ d,

dependency$ dep,

obj$ p,

user$ u

where d.obj# = dep.d_obj#

and p.obj# = dep.p_obj#

and d.remoteowner is null

and p.owner# = :1

and d.owner# = u.user#

and p.type# in (4,5,7,8,9,10,11,12,13,14,22,87)

and ((u.type# != 2 and bitand(u.spare1, 16) = 0

and u.user#!= p.owner#)

or (d.type# not in 4,5,7,8,9,10,11,12,13,14,22,87)))

dba_dependencies

333

PARSING IN CURSOR #3 len=487 dep=1 uid=0 oct=3 ...

select d.owner#,

u.name,

d.name,

d.namespace,

d.stime

from obj$ d,

dependency$ dep,

obj$ p,

user$ u

where d.obj# = dep.d_obj#

and p.obj# = dep.p_obj#

and d.remoteowner is null

and p.owner# = :1

and d.owner# = u.user#

and p.type# in (4,5,7,8,9,10,11,12,13,14,22,87)

and ((u.type# != 2 and bitand(u.spare1, 16) = 0

and u.user#!= p.owner#)

or (d.type# not in 4,5,7,8,9,10,11,12,13,14,22,87)))

dba_dependencies

object_type

334

PARSING IN CURSOR #3 len=487 dep=1 uid=0 oct=3 ...

select d.owner#,

u.name,

d.name,

d.namespace,

d.stime

from obj$ d,

dependency$ dep,

obj$ p,

user$ u

where d.obj# = dep.d_obj#

and p.obj# = dep.p_obj#

and d.remoteowner is null

and p.owner# = :1

and d.owner# = u.user#

and p.type# in (4,5,7,8,9,10,11,12,13,14,22,87)

and ((u.type# != 2 and bitand(u.spare1, 16) = 0

and u.user#!= p.owner#)

or (d.type# not in 4,5,7,8,9,10,11,12,13,14,22,87)))

object_type

editions_enabled

335

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

336

table = data store

for all versions...

337

online upgrade ...

338

... is not just editions

339

editions

ddl_timeout

invisible indexes

column naming

create index online

fallback

version control

constraints

340

existing processes / scripts

341

drop

342

rename

343

edition v1

edition v2

T1 T2

T2 T1

344

edition v1

edition v2

col1 NUMBER

col1 DATE

_v1

_v2

345

edition v1

edition v2

T1 (PK=col1,col2)

T1 (PK=col1,col3)

346

contexts

database links

queues

VPD

FGA

347

348

349

wrap up

350

lots of things not covered

351

11g / 11.2 very very nice

352

don't get too carried away

353

"Oracle 11g is the greatest

invention in the history of man"

- Anon, 2008

Connor McDonald

OracleDBA

co

.uk

355

356

ORA-00041

www.oracledba.co.uk

“active time limit exceeded - session terminated”

357

<apology>

The presentation author apologises

for the gratuitous use of family album

shots, but since his whole family

came to Melbourne for InSync,

he didn't have much choice.

<apology>