Connor McDonald 11g for developers
-
Upload
insync-conference -
Category
Technology
-
view
1.935 -
download
3
description
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>