Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Connor McDonald 11g for developers

2,276 views

Published on

11g for developers

Published in: Technology
  • Very interesting and helpful - thanks!

    Atish
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Connor McDonald 11g for developers

  1. 1. NOTE itty bitty fonts in this presentation SQL> exec sample_font Can you read this ? 1
  2. 2. Connor McDonald OracleDBA co.uk 2
  3. 3. 3
  4. 4. bio slide 4
  5. 5. Connor McDonald
  6. 6. 6
  7. 7. "why bother?" 7
  8. 8. 2007 2008 2009 2010 2011 2012 2013 2014 2015 11g 11.1.0.7 11.2 11g desupported management visibility 11.1.0.6
  9. 9. "why bother?" (part 2) 9
  10. 10. don’t reinvent
  11. 11. there's a lot in 11g ! 12
  12. 12. <apology> </apology>
  13. 13. some cool things.... 14
  14. 14. some not so cool things.... 15
  15. 15. "11g is now production" 16
  16. 16. 17
  17. 17. 11g ≠ 18
  18. 18. 19
  19. 19. coolness barometer 20
  20. 20. first impressions 21
  21. 21. 22
  22. 22. ORA-01017: invalid username/password; logon denied 23
  23. 23. ORA-28000: the account is locked 24
  24. 24. case sensitive passwords 25
  25. 25. default profile tightened 26
  26. 26. password complexity 27
  27. 27. be patient 28
  28. 28. 29
  29. 29. snippets 30
  30. 30. snippets #1: sqlplus BLOBS 31
  31. 31. 10g and below 32
  32. 32. SQL> select PASSPORT_PHOTO 2 from PERSON 3 where surname = 'MCDONALD' 4 / SP2-0678: Column type can not be displayed by SQL*Plus 33
  33. 33. SQL> select PASSPORT_PHOTO 2 from PERSON 3 where surname = 'MCDONALD' 4 / MUGSHOT_BLOB ----------------------------------------------------- D0CF11E0A1B11AE1000000000000000000000000000000003E000 02300000001000000FEFFFFFF0000000020000000 34
  34. 34. snippets #2: sqlplus error logging 35
  35. 35. SQL> set errorlogging on 36
  36. 36. 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 37
  37. 37. 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 38
  38. 38. 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 39
  39. 39. SQL> set errorlogging on SQL> @create_all_objects installation scripts works on 10g too… 40
  40. 40. snippets #3: sqlplus transaction safety 41
  41. 41. 42
  42. 42. SQL> set exitcommit 43
  43. 43. snippets #4: dbms_utility.get_sql_hash 44
  44. 44. SQL> select hash_value 2 from v$sql 3 where sql_text = 'SELECT 99 FROM DUAL'; HASH_VALUE ---------- 835694897 45
  45. 45. SQL> declare 2 h1 raw(16); 3 h2 number; = 835694897 4 n int; 5 begin 6 n := 7 dbms_utility.get_sql_hash( 8 'SELECT 99 FROM DUAL'||chr(0) ,h1,h2); 9 dbms_output.put_line(h1); 10 end; 11 / F1D44D227DC0C4E0C719280B31B1CF31 31B1CF31 46
  46. 46. snippets #5: listagg 47
  47. 47. classical problem 48
  48. 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
  49. 49. DEPTNO MEMBERS ---------- ------------------------------------- 10 CLARK,KING,MILLER 20 SMITH,JONES,SCOTT,ADAMS,FORD 30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES 50
  50. 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 - Rob Van Wijk 51
  51. 51. 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 - Anon 52
  52. 52. 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; - Laurent Schneider 53
  53. 53. 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 / - Tom Kyte 54
  54. 54. 55
  55. 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
  56. 56. Feature: real time sql monitoring 57
  57. 57. 58
  58. 58. 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 59
  59. 59. v$sql_plan 60
  60. 60. ----------------------------------------------------------------------------- | 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
  61. 61. 62
  62. 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
  63. 63. Feature: statistics enhancements 67 67
  64. 64. 68
  65. 65. 69
  66. 66. cardinality is everything 70 70
  67. 67. same with Oracle 71 71
  68. 68. some real(ish) data 72 72
  69. 69. 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 73
  70. 70. default stats not enough 74 74
  71. 71. 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 75
  72. 72. histogram 76 76
  73. 73. 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 77
  74. 74. 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 78
  75. 75. make AND model 79 79
  76. 76. 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 80
  77. 77. three things 81 81
  78. 78. 50% of Holdens are Commodores 82 82
  79. 79. 83
  80. 80. 84 84
  81. 81. no correlation 10g and before 85 85
  82. 82. ---------------------------------------------------------- | Id | Operation | Rows | Bytes | ---------------------------------------------------------- | 0 | SELECT STATEMENT | 1 | 14 | | 1 | SORT AGGREGATE | 1 | 14 | | 2 | BITMAP CONVERSION COUNT | 39527 | 540K| 86 86
  83. 83. SQL> select count(*) from VEHICLE where model = 'COMMODORE'; COUNT(*) ---------- 214468 SQL> select count(*) from VEHICLE where make = 'HOLDEN'; COUNT(*) ---------- 415387 Prob(xy)=Prob(x)*Prob(y) SQL> select (214468/2157079)* 2 (415387/2157079)* 3 2157079 EST_ROWS from dual; EST_ROWS --------------- 41299.9334 ≈ 39527 87 87
  84. 84. 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 88
  85. 85. 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 / SQL> begin 2 dbms_stats.gather_table_stats(user,'VEHICLE', PL/SQL procedure method_opt=> completed. 3 successfully 4 'for columns (make,model) size 254'); 5 end; 6 / PL/SQL procedure successfully completed. 89 89
  86. 86. 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 90
  87. 87. actual versus estimate 91 91
  88. 88. 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 92
  89. 89. its just another column 93 93
  90. 90. 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 94
  91. 91. forget ... 95 95
  92. 92. 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 96
  93. 93. 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 97
  94. 94. 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 98
  95. 95. virtual column 99 99
  96. 96. SYS_OP_COMBINED_HASH 100 100
  97. 97. hash means equality 101 101
  98. 98. 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 102
  99. 99. can we solve this ? 103 103
  100. 100. two enhancements 104 104
  101. 101. adaptive cursor sharing 11.1 105 105
  102. 102. 11.2 106 106
  103. 103. much much better 107
  104. 104. 108
  105. 105. recall 109 109
  106. 106. cardinality 110 110
  107. 107. actual versus estimate 111 111
  108. 108. employ someone.... 112 112
  109. 109. 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')); "ok" ----------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | ----------------------------------------------------------------- | 1 | SORT AGGREGATE | | 1 | 1 | 1 | |* 2 | TABLE ACCESS FULL| VEHICLE | 1 | 220K| 214K| ----------------------------------------------------------------- 113 113
  110. 110. 114 114
  111. 111. but just maybe .... 115 115
  112. 112. ... someone already is 116 116
  113. 113. 100,000 rows 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; 100 rows SQL> create table DEPT as 2 select rownum deptno, 3 'dept'||rownum dname 4 from dual 5 connect by rownum <= 100; 117
  114. 114. 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
  115. 115. SQL> select e.empno, d.dname hard to 2 from emp e, dept d 3 where d.deptno = e.deptno optimize 4 and e.jobid = 1 5 and e.salary > 5000; 4 and e.jobid = 1 no rows selected 5 and e.salary > 5000; ---------------------------------------------------------------- | 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
  116. 116. re-run the query 120
  117. 117. no changes to anything 121
  118. 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 | HASH JOIN | | 89 | 2136 | | 2 | TABLE ACCESS FULL| DEPT | 1 | 10 | |* 3 | TABLE ACCESS FULL| EMP | 4444 | 62216 | --------------------------------------------------- 122
  119. 119. 11.2 123
  120. 120. the optimizer knows what "hard" is 124
  121. 121. cardinality feedback loop 125
  122. 122. its not continuous learning 126
  123. 123. several restrictions 127
  124. 124. SQL tuning advisor fallback 128
  125. 125. Feature: result cache 129
  126. 126. 130
  127. 127. 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 ... 131
  128. 128. cache the results of queries 132
  129. 129. GTT, plsql table, ... hard... single session, expiry issues... 133
  130. 130. memory 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 % 134
  131. 131. 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] 135
  132. 132. 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] 136
  133. 133. 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] 137
  134. 134. 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] 138
  135. 135. cross session 139
  136. 136. session 1 SQL> select /*+ RESULT_CACHE */ owner, count(*) 2 from T 3 group by owner 4 / 29 rows selected. Elapsed: 00:00:03.80 session 2 SQL> select /*+ RESULT_CACHE */ owner, count(*) 2 from T 3 group by owner 4 / 29 rows selected. Elapsed: 00:00:00.04 140
  137. 137. automatic expiry 141
  138. 138. 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 / active txn Elapsed: 00:00:03.91 142
  139. 139. SQL> commit; Commit complete. SQL> select /*+ RESULT_CACHE */ owner, count(*) 2 from T 3 group by owner 4 / Elapsed: 00:00:03.91 reinstantiate cache SQL> select /*+ RESULT_CACHE */ owner, count(*) 2 from T 3 group by owner 4 / Elapsed: 00:00:00.04 voila! 143
  140. 140. 11.2 144
  141. 141. part of table definition 145
  142. 142. alter table T result_cache (mode force); 146
  143. 143. dependencies 147
  144. 144. v$result_cache_objects v$result_cache_dependency 148
  145. 145. 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 149
  146. 146. plsql too 150
  147. 147. 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" 151
  148. 148. currency conversion function 152
  149. 149. slower... obscure... SOA ...awfully complicated 153
  150. 150. 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. 154
  151. 151. SQL> select sum(CURRENCY_CONVERT(crncy)*amount) tot 2 from COUNTRY_SALES 3 / TOT ---------- 4799.62 Elapsed: 00:00:45.36 155
  152. 152. 156
  153. 153. 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. 157
  154. 154. SQL> select sum(CURRENCY_CONVERT(crncy)*amount) tot 2 from COUNTRY_SALES 3 where rownum < 100 4 / TOT ---------- 4799.62 inter-row Elapsed: 00:00:15.78 cache benefit SQL> / TOT ---------- 4799.62 all values Elapsed: 00:00:00.02 cached 158
  155. 155. explain plan 159
  156. 156. 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 160
  157. 157. SQL> select status 2 from v$result_cache_objects 3 where cache_id = 'b82qdu5m139yr3fbna1x5r6g2d'; STATUS --------- Published ? New - Published - Result is still under construction 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 161
  158. 158. select /*+ RESULT_CACHE */ … two people, same query select /*+ RESULT_CACHE */ … 162
  159. 159. when in doubt... ...try to break it 163
  160. 160. 164
  161. 161. 165
  162. 162. 166
  163. 163. 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. 167
  164. 164. 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 | -------------------------------------------------------------------------- 168
  165. 165. SQL> select /*+ RESULT_CACHE */ owner, slow(object_id) 2 from T 3 where rownum < 120; [5 seconds later...] OWNERSQL> select status SLOW(OBJECT_ID) 2 from v$result_cache_objects ------------------------------ --------------- SYS 3 where cache_id = '14tnr7dxmvkp3244d69tw72z4p'; 20 SYS 46 SYS STATUS 2 session 28 SYS --------- 15 SYS New 29 SQL> select /*+ RESULT_CACHE */ owner, slow(object_id) [still from 2 executing...] T 3 where rownum < 120; [executing...] Elapsed: 00:03:03.54 !!!!!!!!! 169
  166. 166. 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.... 170
  167. 167. 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] 171
  168. 168. better in 11.2 172
  169. 169. 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 ... ... 173
  170. 170. "take care....." 174
  171. 171. 175
  172. 172. not too short.... why bother with result cache? 176
  173. 173. not too long.... might lock other people out 177
  174. 174. Feature: compound triggers 178
  175. 175. example: table audit 179
  176. 176. 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) 180
  177. 177. 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. 181
  178. 178. works but slow... 182
  179. 179. SQL> insert into T 2 select owner, object_name 3 from all_objects insert where 4 into T rownum <= 10000; select owner, object_name from all_objects 10000 rownum <= 10000 where rows created. 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 183
  180. 180. bulk binding "hard" 184
  181. 181. 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; / 185
  182. 182. create or replace trigger AUDIT_TRG1 before insert or update or delete on T begin t_pkg.g.delete; end; / 186
  183. 183. 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; / 187
  184. 184. 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; / 188
  185. 185. SQL> insert into T 2 select owner, object_name 3 from all_objects insert into T 4 where rownum <= 10000; select owner, object_name from all_objects 10000 rows created. 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 189
  186. 186. additional package no one did it .... three triggers 190
  187. 187. 11g compound triggers 191
  188. 188. 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; / 192
  189. 189. 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 / 193 Trigger created.
  190. 190. one more thing on triggers... 194
  191. 191. the 107 slides you didn't see 195
  192. 192. 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 196
  193. 193. 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 197
  194. 194. 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 198
  195. 195. 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 199
  196. 196. etc etc etc 200
  197. 197. Which of the following is the largest ? 201
  198. 198. T 202
  199. 199. 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 203
  200. 200. Feature: 11g disabled triggers 204
  201. 201. 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. 205
  202. 202. SQL> select status from user_triggers 2 where trigger_name = 'AUDIT_TRG'; STATUS -------- DISABLED SQL> insert into T values ('X','Y'); 1 row created. 206
  203. 203. Feature: Dependency tracking 207
  204. 204. 10g and below 208
  205. 205. 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. 209
  206. 206. SQL> alter table T add Z number; Table altered. SQL> select status 2 from user_objects 3 where object_name = 'MY_VIEW'; STATUS ------- INVALID 210
  207. 207. 11g 211
  208. 208. better granularity 212
  209. 209. SQL> alter table T add Z number; Table altered. SQL> select status 2 from user_objects 3 where object_name = 'MY_VIEW'; STATUS ------- VALID 213
  210. 210. plsql too 214
  211. 211. quick review 215
  212. 212. "always use packages" 216
  213. 213. ALL production code ! 217
  214. 214. 218
  215. 215. break the invalidation chain 219
  216. 216. proc A proc B proc C proc D pack A pack B pack C pack D body A body B body C body D 220
  217. 217. 11g 221
  218. 218. change the spec as well ! 222
  219. 219. pack A pack B pack C pack D body A body B body C body D 223
  220. 220. SQL> create or replace 2 package PKG is 3 procedure P1; 4 end; 5 / SQL> create or replace Package created. 2 procedure PRC is 3 begin SQL> create or replace 4 pkg.p1; 2 package body PKG is 3 5 end; procedure P1 is 4 x6 / number; 5 begin 6 Procedure created. x := 1; 7 end; 8 end; 9 / Package body created. 224
  221. 221. 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. 225
  222. 222. SQL> select status 10g and below 2 from user_objects 3 where object_name = 'PRC'; STATUS ------- INVALID SQL> select status 11g 2 from user_objects 3 where object_name = 'PRC'; STATUS ------- VALID 226
  223. 223. package D 227
  224. 224. the order is important 228
  225. 225. 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. 229
  226. 226. 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. 230
  227. 227. moral of the story 231
  228. 228. change package bodies (as before) 232
  229. 229. add to bottom of specs 233
  230. 230. this is NOT about package state 234
  231. 231. 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. 235
  232. 232. SQL> create or replace 2 procedure PRC is 3 begin SQL> create or replace 4 pkg.p1; 2 package body PKG is 5 end; 3 6 / 4 my_global_var date; 5 Procedure created. 6 procedure p1 is 7 x number; SQL> exec PRC; 8 begin 9 if my_global_var is null then SQL> exec PRC; 10 my_global_var := sysdate; 11 end if; BEGIN PRC; END; 12 end; 13 end; * 14 / ERROR at line 1: ORA-04068: existing state of packages has been discarded Package body created. 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 236
  233. 233. minimise global variables keep stateful data separate store types separately 237
  234. 234. you may have noticed... 238
  235. 235. 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. 239
  236. 236. Direct sequence access 240
  237. 237. 241
  238. 238. can we reduce the risk further ? 242
  239. 239. Feature: editions 243
  240. 240. SQL> create or replace 2 procedure THE_SINGLE_MOST_IMPORTANT_PROC_IN_MY_APP is begin .... 244
  241. 241. 11.2 245
  242. 242. 246
  243. 243. "version control" 247
  244. 244. package PKG is package PKG(V2) is select COL1, COL2 select COL1, NEW_COL from MY_VIEW from MY_VIEW(V2) both in active use ! 248
  245. 245. SQL> desc DBA_EDITIONS Name Null? Type ----------------------------- -------- ------------- EDITION_NAME NOT NULL VARCHAR2(30) PARENT_EDITION_NAME VARCHAR2(30) USABLE VARCHAR2(3) 249
  246. 246. SQL> select * 2 from DBA_EDITIONS; EDITION_NAME PARENT_EDITION USABLE ------------ -------------- ------ ORA$BASE YES 250
  247. 247. PKG1 PKG2 PKG3 PKG4 PKG5 ora$base PKG1 PKG3 PKG5 version2 251
  248. 248. no space = probably editionable 252
  249. 249. indexes 253
  250. 250. Invisible indexes 254
  251. 251. tables 255
  252. 252. views 256
  253. 253. create view V_MY_TABLE as select V1_COL1 as col1, V1_COL2 as col2, version1 V1_COL3 as col3, V1_ONLY_COL4 as col4, from MY_TABLE 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 create view V_MY_TABLE as select V1_COL1 as col1, V1_COL2 as col2, V1_COL3 as col3, version2 V2_NEWCOL5 as col5, V2_NEWCOL6 as col6 from MY_TABLE 257
  254. 254. editioning views (special) 258
  255. 255. basic example 259
  256. 256. 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) 260
  257. 257. 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. 261
  258. 258. version 2 262
  259. 259. SQL> desc EMP Name Null? Type ----------------------------- -------- ------------- EMPNO NOT NULL NUMBER(4) ENAME VARCHAR2(10) JOB VARCHAR2(9) MGR NUMBER(4) HIREDATE Contract/Permanent DATE SAL NUMBER(7,2) COMM NUMBER(7,2) DEPTNO NUMBER(2) ETYPE VARCHAR2(10) TERMINATION_DATE DATE End of Contract 263
  260. 260. old style 264
  261. 261. 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. 265
  262. 262. broken application 266
  263. 263. 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 267
  264. 264. outage 268
  265. 265. 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. 269
  266. 266. now with editions 270
  267. 267. step 1 271
  268. 268. enable editions 272
  269. 269. SQL> alter user SCOTT enable editions; User altered. 273
  270. 270. this is a big deal 274
  271. 271. Enabling editions is retroactive and irreversible. - 11g2 doc 275
  272. 272. step 2 276
  273. 273. abstract your tables 277
  274. 274. 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. 278
  275. 275. obtuse _EMP 279
  276. 276. SQL> select * from _EMP; select * from _EMP * ERROR at line 1: ORA-00911: invalid character 280
  277. 277. may mean an outage as you upgrade to 11.2 281
  278. 278. 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. 282
  279. 279. create an edition 283
  280. 280. SQL> create edition "APP_V2" 2 / Edition created. 284
  281. 281. SQL> conn SCOTT/TIGER Connected. SQL> alter session set edition = APP_V2; ERROR: ORA-38802: edition does not exist 285
  282. 282. SQL> grant USE on edition APP_V2 to SCOTT; Grant succeeded. 286
  283. 283. SQL> alter session set edition = APP_V2; SQL> create or replace 2 editioning view EMP as 3 select * from "_EMP" 4 / View created. 287
  284. 284. 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) 288
  285. 285. 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 289
  286. 286. SQL> select sys_context('USERENV', 2 'CURRENT_EDITION_NAME') edt 3 from dual; EDT -------------- APP_V2 290
  287. 287. 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. 291
  288. 288. 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. 292
  289. 289. 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. 293
  290. 290. we're close.... 294
  291. 291. ETYPE not null 295
  292. 292. 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. 296
  293. 293. constraints not (natively) editionable 297
  294. 294. 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. 298
  295. 295. APP_V2 "everyone has an ETYPE" cross edition consistency APP_V1 (aka ORA$BASE) "what is an ETYPE" 299
  296. 296. cross edition triggers 300
  297. 297. 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. 301
  298. 298. 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. 302
  299. 299. both in the new edition "the working edition is sacred" 303
  300. 300. SQL> alter session set edition = APP_V2; Session altered. SQL> alter trigger EMP_V1_TO_V2 enable; Trigger altered. 304
  301. 301. all new / modified data 305
  302. 302. historical data uncommitted data 306
  303. 303. 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. 307
  304. 304. 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 308
  305. 305. or DBMS_SQL 309
  306. 306. or DBMS_PARALLEL_EXECUTE 310
  307. 307. voila ! 311
  308. 308. move people over 312
  309. 309. 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 / 313
  310. 310. 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 / 314
  311. 311. retire old edition optional 315
  312. 312. how do I get started 316
  313. 313. first.... come clean 317
  314. 314. 318
  315. 315. stop ... taking ... outages 319
  316. 316. before you start 320
  317. 317. 321
  318. 318. more complicated than you think.... 322
  319. 319. enabling editions 323
  320. 320. probably the whole database 324
  321. 321. cross user consistency 325
  322. 322. 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 326
  323. 323. SQL> alter user TO_BE_EDITIONED enable editions FORCE; User altered. 327
  324. 324. 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 328
  325. 325. possibly not so "online" 329
  326. 326. 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 330
  327. 327. 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))) 331
  328. 328. PARSING IN CURSOR #3 len=487 dep=1 uid=0 oct=3 ... select d.owner#, u.name, d.name, dba_dependencies 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
  329. 329. PARSING IN CURSOR #3 len=487 dep=1 uid=0 oct=3 ... select d.owner#, u.name, d.name, dba_dependencies d.namespace, d.stime from obj$ d, dependency$ dep, obj$ p, user$ u object_type 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))) 333
  330. 330. 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 object_type where d.obj# = dep.d_obj# and and p.obj# = dep.p_obj# d.remoteowner is null editions_enabled 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))) 334
  331. 331. 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 335
  332. 332. table = data store for all versions... 336
  333. 333. online upgrade ... 337
  334. 334. ... is not just editions 338
  335. 335. version control create index online ddl_timeout fallback editions constraints column naming invisible indexes 339
  336. 336. existing processes / scripts 340
  337. 337. drop 341
  338. 338. rename 342
  339. 339. edition v1 T1 T2 edition v2 T2 T1 343
  340. 340. edition v1 col1 _v1 NUMBER edition v2 col1 _v2 DATE 344
  341. 341. edition v1 T1 (PK=col1,col2) edition v2 T1 (PK=col1,col3) 345
  342. 342. contexts database links queues VPD FGA 346
  343. 343. 347
  344. 344. 348
  345. 345. wrap up 349
  346. 346. lots of things not covered 350
  347. 347. 11g / 11.2 very very nice 351
  348. 348. don't get too carried away 352
  349. 349. "Oracle 11g is the greatest invention in the history of man" - Anon, 2008 353
  350. 350. Connor McDonald OracleDBA co.uk 355
  351. 351. ORA-00041 “active time limit exceeded - session terminated” www.oracledba.co.uk 356
  352. 352. <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> 357

×