Sep13 sql tuning_101

789 views

Published on

OOW13

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
789
On SlideShare
0
From Embeds
0
Number of Embeds
13
Actions
Shares
0
Downloads
0
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Sep13 sql tuning_101

  1. 1. Connor McDonald OracleDBA co.uk 1 @connor_mc_d connormcdonald.wordpress.com
  2. 2. 2
  3. 3. gratuitous book plug 4
  4. 4. bio slide 5
  5. 5. 7
  6. 6. 8
  7. 7. you should look cool 9
  8. 8. 10
  9. 9. 11 Dump of memory from 0x07246400 to 0x07248400 1064B4C00 06A20000 08C0000A 0A07C47E 00020506 [...........~....] 1064B4C10 34BC0000 01000000 00030CBF 0A07C47C [4..............|] 1064B4C20 0002EC28 00020300 00000000 0004001D [...(............] ... 1064B6BF0 C10B02C1 0B06436F 6E6E6F72 C47E0605 [......Connor.~..] table or index block size database version created in relative block address
  10. 10. 12
  11. 11. sounds sexy right ? 13
  12. 12. 14
  13. 13. if you are tuning SQL ... 15
  14. 14. ... you are failing 16
  15. 15. 17
  16. 16. why ? 18
  17. 17. real example 19
  18. 18. 20
  19. 19. 21 "last transaction for all accounts"
  20. 20. problem 22
  21. 21. 23
  22. 22. make it faster ... 24
  23. 23. "it’s a SQL problem" 25
  24. 24. 26 SQL> desc ACCOUNT Name Null? Type ----------------------------------- -------- ------------------------ ACCOUNT_NUM NOT NULL NUMBER(8) CURRENT_BALANCE NOT NULL NUMBER(14,2) ... SQL> desc TRANSACTIONS Name Null? Type ----------------------------------- -------- ------------------- TXN_SEQ NOT NULL NUMBER(11) TXN_TS NOT NULL TIMESTAMP(6) TXN_TYPE NOT NULL VARCHAR2(10) ACCOUNT_NUM NOT NULL NUMBER(8) AMOUNT NOT NULL NUMBER(11,2)
  25. 25. existing code 27
  26. 26. 28 SQL> select ACCOUNT_NUM, max(TXN_TS) LAST_TS 2 from TRANSACTIONS, ACCOUNT 3 where <joins etc> 4 group by ACCOUNT_NUM 5 order by 1;
  27. 27. 29 SQL> select ACCOUNT_NUM, max(TXN_TS) LAST_TS 2 from TRANSACTIONS 3 group by ACCOUNT_NUM 4 order by 1; simplified
  28. 28. 30 SQL> select ACCOUNT_NUM, max(TXN_TS) LAST_TS 2 from TRANSACTIONS t 3 group by ACCOUNT_NUM 4 order by 1; -------------------------------------------------- | Id | Operation | Name | -------------------------------------------------- | 0 | SELECT STATEMENT | | | 1 | TABLE ACCESS FULL | TRANSACTIONS | --------------------------------------------------
  29. 29. tuning attempt #1 31
  30. 30. 32 SQL> select /*+ PARALLEL(t 16) */ 2 ACCOUNT_NUM, max(TXN_TS) LAST_TS 3 from TRANSACTIONS t 4 group by ACCOUNT_NUM 5 order by 1;
  31. 31. worked... 33
  32. 32. ... storage meltdown 34
  33. 33. tuning attempt #2 35
  34. 34. 36 create index TRANSACTIONS_IX on TRANSACTIONS ( account_num, txn_ts ) SQL> select ACCOUNT_NUM, max(TXN_TS) LAST_TS 2 from TRANSACTIONS t 3 group by ACCOUNT_NUM 4 order by 1; -------------------------------------------------- | Id | Operation | Name | -------------------------------------------------- | 0 | SELECT STATEMENT | | | 1 | INDEX FAST FULL SCAN| TRANSACTIONS_IX | --------------------------------------------------
  35. 35. worked... 37
  36. 36. ... oltp impact 38
  37. 37. tuning attempt #3 39
  38. 38. 40 CREATE TABLE TRANSACTIONS ( ... ) PARTITION BY RANGE (TXN_TS) INTERVAL( NUMTOYMINTERVAL(1,'MONTH')) ( PARTITION P1 VALUES LESS THAN (TIMESTAMP' 2009-01-01 00:00:00') PARTITION P2 VALUES LESS THAN (TIMESTAMP' 2009-06-01 00:00:00') ... );
  39. 39. 41 SQL> select ACCOUNT_NUM, max(TXN_TS) LAST_TS 2 from TRANSACTIONS t 3 where TXN_TS > add_months(sysdate,-12) 4 group by ACCOUNT_NUM 5 order by 1;
  40. 40. 42 --------------------------------------------------------------- | Id | Operation | Name |Pstart| Pstop | -------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | 1 | PARTITION RANGE ITER..| | 127 | 138 | |* 2 | TABLE ACCESS FULL | TRANSACTIONS | 127 | 138 | -------------------------------------------------------------
  41. 41. worked ... 43
  42. 42. ... changed the function 44
  43. 43. 45
  44. 44. tuning attempt #4 47
  45. 45. 48 Jul Aug Sep Oct
  46. 46. 49 SQL> insert into GTT_LAST_TXN 2 select ACCOUNT_NUM, max(TXN_TS) LAST_TS 3 from TRANSACTIONS t 4 where TXN_TS >= trunc(sysdate,'MM') 5 group by ACCOUNT_NUM; for i in ( select ACCOUNT_NUM from ACCOUNTS minus select ACCOUNT_NUM from GTT_LAST_TXN ) insert into GTT_LAST_TXN select /*+ INDEX_DESC(t (account_num, txn_ts)) */ MAX(TXN_TS) from TRANSACTIONS t where ACCOUNT_NUM = i.ACCOUNT_NUM and TXN_TS < trunc(sysdate,'MM')
  47. 47. worked ... 50
  48. 48. ... complexity ! 51
  49. 49. problem 52
  50. 50. 53 SQL> select ... 2 from ... 3 where ...
  51. 51. the requirement 54
  52. 52. 55 "we have an interest in recent activity for account holders" "last transaction for all accounts"
  53. 53. promotional material 56 "we haven't seen you in a while, here's a discount on ...."
  54. 54. 57
  55. 55. manual examination 58
  56. 56. tuning attempt #5 59
  57. 57. 60 SQL> desc ACCOUNT Name Null? Type ----------------------------------- -------- --------------- ACCOUNT_NUM NOT NULL NUMBER(8) CURRENT_BALANCE NOT NULL NUMBER(14,2) ... ... ... MODIFICATION_TS NOT NULL TIMESTAMP(6)
  58. 58. optimistic locking 61
  59. 59. 62 select ..., MODIFICATION_TS into ..., :prev_modtstamp from ACCOUNT where ... update ACCOUNT set ... where ACCOUNT_NUM = :b1 and MODIFICATION_TS = :prev_modtstamp if SQL%NOTFOUND then msg('Row has been changed by another user, please requery'); end if;
  60. 60. 63 SQL> select ACCOUNT_NUM, 2 MODIFICATION_TS approx_last_usage 3 from ACCOUNT
  61. 61. that's it ! 64
  62. 62. later ... 65
  63. 63. 66 SQL> desc ACCOUNT Name Null? Type ------------------------------- -------- -------------- ACCOUNT_NUM NOT NULL NUMBER(8) CURRENT_BALANCE NOT NULL NUMBER(14,2) ...
  64. 64. 67 update ACCOUNT set ... where ACCOUNT_NUM = :b1 and MODIFICATION_TS = :prev_modtstamp LAST_TXN_TS = systimestamp LARGEST_TXN_AMT = greatest(TXN_AMT,LARGEST_TXN_AMT) BALANCE_CEILING = greatest(BALANCE,BALANCE_CEILING) BALANCE_FLOOR = least(BALANCE,BALANCE_FLOOR)
  65. 65. 68 SQL> desc ACCOUNT Name Null? Type ----------------------------------- -------- --------------- ACCOUNT_NUM NOT NULL NUMBER(8) CURRENT_BALANCE NOT NULL NUMBER(14,2) LAST_WITHDRAWAL_TS TIMESTAMP(6) LAST_DEPOSIT_TS TIMESTAMP(6) LAST_TXN_TS TIMESTAMP(6) LARGEST_TXN_AMT NUMBER(14,2) BALANCE_CEILING NUMBER(14,2) BALANCE_FLOOR NUMBER(14,2)
  66. 66. minimal cost 69
  67. 67. (semi) automate 70 "we haven't seen you in a while, here's a discount on ...."
  68. 68. too focused on the SQL 71
  69. 69. so... 72
  70. 70. if you don't tune SQL ... 73
  71. 71. ...what are you tuning ? 74
  72. 72. 75 HERE
  73. 73. user experience 76
  74. 74. UX 77
  75. 75. screen... 78
  76. 76. ... user experience 79
  77. 77. report.... 80
  78. 78. ... user experience 81
  79. 79. nightly batch... 82
  80. 80. ... user experience 83
  81. 81. all solutions shown ... 84 denormalised indexes structure horse power
  82. 82. ... all valid 85
  83. 83. as long as 86
  84. 84. tuning the requirement 87
  85. 85. tuning the user experience 88
  86. 86. SQL as a means, not an end 89
  87. 87. </rant> 90
  88. 88. so if we're "failing"… 91
  89. 89. …why talk about 92
  90. 90. 93
  91. 91. 94
  92. 92. sql tuning is ... 95
  93. 93. 96
  94. 94. stop the bleeding... 97
  95. 95. ...until find a cure 98
  96. 96. but ... without 99
  97. 97. ... side effects 100
  98. 98. every pain problem 101
  99. 99. 102
  100. 100. ... side effects 103
  101. 101. 104 constipation dizziness drowsiness headache lightheadedness nausea mood swingssweating vomitingrash itching difficulty breathing tightness in the chest swelling of the mouth confusion disorientation fainting irregular heartbeat hallucinations seizures sudden chest pain unusual bruising or bleeding blurred vision
  102. 102. "This is not a complete list" 105
  103. 103. triage 106 find the (likely) pain stop the bleeding avoid side effects work toward cure
  104. 104. find 107
  105. 105. 108
  106. 106. where not too look ... 109 (maybe)
  107. 107. server 110
  108. 108. "server CPU is 45%" 111 "buffer cache is 99%"
  109. 109. too high level 112
  110. 110. user experience 113
  111. 111. "no problems last 15 minutes" 114
  112. 112. Statspack 115 (maybe)
  113. 113. hourly... 116
  114. 114. sql trace 117
  115. 115. definitive ... but 118
  116. 116. (maybe) intrusive 119
  117. 117. (maybe) user experience 120
  118. 118. "please repeat" 121
  119. 119. targetted 122
  120. 120. much easier 123
  121. 121. instrumented 124
  122. 122. 125 procedure MY_PROC(...) is begin dbms_application_info.set_module('MY_PROC'); dai.set_client_info(' p_parm1 = '||p_parm1); dai.set_client_info(' p_parm2 = '||p_parm2); select ... update ... dai.set_action('now loading changes'); ... end;
  123. 123. diagnostic pack
  124. 124. v$active_session_history 127
  125. 125. amazing 128
  126. 126. every active session... 129
  127. 127. ...every second 130
  128. 128. 131 SQL> desc V$ACTIVE_SESSION_HISTORY Name Null? Type ------------------------------- -------- ------------------- SAMPLE_ID NUMBER SAMPLE_TIME TIMESTAMP(3) IS_AWR_SAMPLE VARCHAR2(1) SESSION_ID NUMBER SESSION_SERIAL# NUMBER SESSION_TYPE VARCHAR2(10) FLAGS NUMBER USER_ID NUMBER SQL_ID VARCHAR2(13) IS_SQLID_CURRENT VARCHAR2(1) SQL_CHILD_NUMBER NUMBER SQL_OPCODE NUMBER SQL_OPNAME VARCHAR2(64) FORCE_MATCHING_SIGNATURE NUMBER TOP_LEVEL_SQL_ID VARCHAR2(13) TOP_LEVEL_SQL_OPCODE NUMBER SQL_PLAN_HASH_VALUE NUMBER SQL_PLAN_LINE_ID NUMBER SQL_PLAN_OPERATION VARCHAR2(30)
  129. 129. "This morning, my screen froze for 3 mins running Pay Adjustment..." 132
  130. 130. 133 SQL> select sql_id, 2 sql_exec_id, 3 count(*) 4 from v$active_session_history 5 where program = 'Finance.exe' 6 and module = 'PayAdjust' 7 and sample_time > timestamp '2013-08-20 08:00:00' 8 and sql_id is not null 9 group by 10 sql_id, 11 sql_exec_id 12 order by 3 desc ;
  131. 131. 134 SQL_ID SQL_EXEC_ID COUNT(*) ------------- ----------- ---------- 087jnbt3bg3fn 33562711 178 9n2nx15wj6tb3 33512732 39 7nvh5pd4y5nqu 33562791 36 7nvh5pd4y5nqu 33562735 30 7nvh5pd4y5nqu 33562736 29 6b5r2j5p2z7kk 33671666 14 6b5r2j5p2z7kk 33670545 12 7nvh5pd4y5nqu 33562689 11 bamffwpy8v8bt 33554432 9 ...
  132. 132. 135 # cd $ORACLE_HOME/rdbms/admin # sqlplus / as sysdba @ashrpt
  133. 133. 136
  134. 134. very very cool 137
  135. 135. 138 SQL> select sql_fulltext 2 from v$sql 3 where sql_id = '087jnbt3bg3fn'; SQL_FULLTEXT ----------------------------------------------- SELECT ... FROM ...
  136. 136. 139 latching
  137. 137. 140 woeful metaphor
  138. 138. 143 same with memory
  139. 139. SGA
  140. 140. 145 latches
  141. 141. 146 serialised access aka, someone waits
  142. 142. SGA protected by
  143. 143. SGA protected by 1) get latch
  144. 144. SGA protected by 2) access memory
  145. 145. SGA protected by 3) release latch
  146. 146. 151 what protects the latch ?
  147. 147. 152 latch acquisition atomic
  148. 148. you can do better 153
  149. 149. 154 SQL> select sql_fulltext 2 from v$sqlstats 3 where sql_id = '087jnbt3bg3fn'; SQL_FULLTEXT ----------------------------------------------- SELECT ... FROM ...
  150. 150. "The column definitions for columns in V$SQLSTATS are identical to those in the V$SQL and V$SQLAREA views. However, the V$SQLSTATS view differs from V$SQL and V$SQLAREA in that it is faster, more scalable, and has a greater data retention (the statistics may still appear in this view, even after the cursor has been aged out of the shared pool)." 155
  151. 151. 156 found your sql...
  152. 152. SQL> select e.department_id, sum(salary) 2 from emp e, 3 job_hist j 4 where e.employee_id = j.employee_id 5 and extract(year from e.hire_date) > 1985 6 and j.end_date > j.start_date + 1 7 and j.start_date >= e.hire_date 8 group by e.department_id 157
  153. 153. stop 158
  154. 154. optimizer got it wrong... 159
  155. 155. or 160
  156. 156. ... it cannot run better 161 legitimate response
  157. 157. be like the optimizer 162 only smarter
  158. 158. what does it do ? 163
  159. 159. we can see ! 164
  160. 160. 10053 165
  161. 161. don't panic.... 166
  162. 162. 167 SQL> alter session set events = 2 '10053 trace name context forever, level 1'; Session altered. SQL> explain plan for 2 select e.empno, d.dname 3 from emp e, 4 dept d 5 where e.deptno = d.deptno 6 and e.ename like '%A%' 7 and d.deptno != 5; Explained.
  163. 163. 168 SQL> select p.tracefile 2 from v$session s, v$process p 3 where s.paddr = p.addr 4 and s.sid = sys_context('USERENV','SID'); TRACEFILE ---------------------------------------------- /u01/app/oracle/diag/..../MYDB_ora_2994270.trc
  164. 164. 169 --------------------- QUERY BLOCK SIGNATURE --------------------- signature (): qb_name=SEL$1 nbfros=2 flg=0 fro(0): flg=4 objn=51562 hint_alias="D"@"SEL$1" fro(1): flg=4 objn=51564 hint_alias="E"@"SEL$1" ****************************************** ----- Current SQL Statement (sql_id=gvg2yvpdr4uaw) ----- explain plan for select e.empno, d.dname from emp e, dept d where e.deptno = d.deptno and e.ename like '%A%' and d.deptno != 5 *******************************************
  165. 165. 170 ****************************** PARAMETERS ****************************** Compilation Environment Dump optimizer_mode_hinted = false optimizer_features_hinted = 0.0.0 parallel_execution_enabled = true parallel_query_forced_dop = 0 parallel_dml_forced_dop = 0 parallel_ddl_forced_degree = 0 parallel_ddl_forced_instances = 0 _query_rewrite_fudge = 90 optimizer_features_enable = 11.2.0.2 _optimizer_search_limit = 5
  166. 166. 171 Considering Query Transformations ************************** ************************* Common Subexpression elimination Order-by elimination Join Elimination ************************* SQL:******* UNPARSED QUERY IS ******* SELECT "E"."EMPNO" "EMPNO","D"."DNAME" "DNAME" FROM "SCOTT"."EMP" "E","SCOTT"."DEPT" "D" WHERE "E"."DEPTNO"="D"."DEPTNO" AND "E"."ENAME" LIKE '%A%' AND "D"."DEPTNO"<>5
  167. 167. 172 Predicate Move-Around (PM) ************************** "E"."DEPTNO"="D"."DEPTNO" AND "E"."ENAME" LIKE '%A%' AND "D"."DEPTNO"<>5 ... finally: "E"."DEPTNO"="D"."DEPTNO" AND "E"."ENAME" LIKE '%A%' AND "D"."DEPTNO"<>5 AND "E"."DEPTNO"<>5
  168. 168. 173 SINGLE TABLE ACCESS PATH Single Table Cardinality Estimation for EMP[E] Table: EMP Alias: E Card: Original: 14.000000 Rounded: 1 Computed: 0.70 Access Path: TableScan Cost: 4.00 Resp: 4.00 Degree: 0 Cost_io: 4.00 Cost_cpu: 41081 Resp_io: 4.00 Resp_cpu: 41081 Best:: AccessPath: TableScan Cost: 4.00 Degree: 1 Resp: 4.00 Card: 0.70 Bytes: 0
  169. 169. 174 Access path analysis for DEPT *************************************** SINGLE TABLE ACCESS PATH Single Table Cardinality Estimation for DEPT[D] Using prorated density: 0.208333 of col #1 as selectvity of out-of-range/non-existent value pred Table: DEPT Alias: D Card: Original: 4.000000 Rounded: 3 Computed: 3.17 Access Path: TableScan Cost: 4.00 Resp: 4.00 Degree: 0 Cost_io: 4.00 Cost_cpu: 36467 Resp_io: 4.00 Resp_cpu: 36467 Best:: AccessPath: TableScan Cost: 4.00 Degree: 1 Resp: 4.00 Card: 3.17 Bytes: 0
  170. 170. 175 Join order[1]: EMP[E]#0 DEPT[D]#1 *************** Now joining: DEPT[D]#1 *************** NL Join Outer table: Card: 0.70 Cost: 4.00 Resp: 4.00 Degree: 1 Bytes: 13 Access path analysis for DEPT Access Path: TableScan Access Path: index (UniqueScan) Index: PK_DEPT
  171. 171. 176 SM Join SM cost: 10.01 Outer table: EMP Alias: E resc: 4.00 card 0.70 bytes: 13 deg: 1 resp: 4.00 Inner table: DEPT Alias: D resc: 4.00 card: 3.17 bytes: 13 deg: 1 resp: 4.00 HA Join HA cost: 8.51 resc: 8.51 resc_io: 8.00 resc_cpu: 4367998 resp: 8.51 resp_io: 8.00 resp_cpu: 4367998 Best:: JoinMethod: NestedLoop Cost: 5.01 Degree: 1 Resp: 5.01 Card: 0.55 Bytes: 26
  172. 172. 177 Join order[2]: DEPT[D]#1 EMP[E]#0 *************** Now joining: EMP[E]#0 *************** NL Join ... SM Join ... HA Join ...
  173. 173. 178 ------------------------------------------------+---------------+ | Id | Operation | Name | Rows | Cost | ------------------------------------------------+---------------- | 0 | SELECT STATEMENT | | | 5 | | 1 | NESTED LOOPS | | | | | 2 | NESTED LOOPS | | 1 | 5 | | 3 | TABLE ACCESS FULL | EMP | 1 | 4 | | 4 | INDEX UNIQUE SCAN | PK_DEPT | 1 | 0 | | 5 | TABLE ACCESS BY INDEX ROWID | DEPT | 1 | 1 | ------------------------------------------------+---------------+
  174. 174. the optimizer does ... 179
  175. 175. can I write it better ? 180 CONSIDERING QUERY TRANSFORMATIONS
  176. 176. where should I start ? 181 SINGLE TABLE ACCESS PATH
  177. 177. what should I join to (next) ? 182 Join order[1]: EMP[E]#0 DEPT[D]#1
  178. 178. how should I join ? 183 NL Join HA Join SM Join
  179. 179. we follow its lead 184
  180. 180. what is the real query 185
  181. 181. 186 SQL> set autotrace traceonly stat SQL> select * from STUFF 2 where CREATED > sysdate Statistics ------------------------------------------ 651 recursive calls 0 db block gets 2243 consistent gets 24 physical reads
  182. 182. 12c 187
  183. 183. 188 SQL> variable c clob SQL> begin 2 dbms_utility.expand_sql_text 3 ( 'select * from STUFF '|| 4 'where created > sysdate',:c); 5 end; 6 / PL/SQL procedure successfully completed. SQL> print c
  184. 184. 189 SQL> create or replace 2 view STUFF as 3 select 4 o.owner, 5 o.created, 6 s.bytes, 7 s.tablespace_name 8 from 9 dba_segments s, 10 all_objects o 11 where o.owner = s.owner 12 and o.object_name = s.segment_name; View created.
  185. 185. 190 SELECT "A1"."OWNER" "OWNER", "A1"."NAME" "NAME", "A1"."CREATED" "CREATED", "A1"."BYTES" "BYTES", "A1"."TABLESPACE_NAME" "TABLESPACE_NAME" FROM (SELECT "A2"."OWNER" "OWNER", "A2"."OBJECT_NAME" "NAME", "A2"."CREATED" "CREATED", "A3"."BYTES" "BYTES", "A3"."TABLESPACE_NAME" "TABLESPACE_NAME" FROM (SELECT "A4" ."OWNER" "OWNER", "A4"."SEGMENT_NAME" "SEGMENT_NAME", "A4"."PARTITION_NAME" "PARTITION_NAME", "A4"."SEGMENT_TYPE" "SEGMENT_TYPE", "A4"."SEGMENT_SUBTYPE" "SEGMENT_SUBTYPE", "A4"."TABLESPACE_NAME" "TABLESPACE_NAME", "A4"."HEADER_FILE" "HEADER_FILE", "A4"."HEADER_BLOCK" "HEADER_BLOCK", DECODE(BITAND("A4"."SEGMENT_FLAGS",131072),131072, "A4"."BLOCKS",DECODE(BITAND("A4"."SEGMENT_FLAGS",1),1, "SYS"."DBMS_SPACE_ADMIN"."SEGMENT_NUMBER_BLOCKS"("A4"."TABLESPACE_ID", "A4"."RELATIVE_FNO", "A4"."HEADER_BLOCK", "A4"."SEGMENT_TYPE_ID", "A4"."BUFFER_POOL_ID", "A4"."SEGMENT_FLAGS", "A4"."SEGMENT_OBJD", "A4"."BLOCKS"), "A4"."BLOCKS"))*"A4"."BLOCKSIZE" "BYTES", DECODE(BITAND("A4"."SEGMENT_FLAGS",131072),131072, "A4"."BLOCKS",DECODE(BITAND("A4"."SEGMENT_FLAGS",1),1, "SYS"."DBMS_SPACE_ADMIN"."SEGMENT_NUMBER_BLOCKS"("A4"."TABLESPACE_ID", "A4"."RELATIVE_FNO",
  186. 186. 191 "A4"."HEADER_BLOCK", "A4"."SEGMENT_TYPE_ID", "A4"."BUFFER_POOL_ID", "A4"."SEGMENT_FLAGS", "A4"."SEGMENT_OBJD", "A4"."BLOCKS"), "A4"."BLOCKS")) "BLOCKS",DECODE(BITAND("A4"."SEGMENT_FLAGS",131072),131072, "A4"."EXTENTS",DECODE(BITAND("A4"."SEGMENT_FLAGS",1),1, "SYS"."DBMS_SPACE_ADMIN"."SEGMENT_NUMBER_EXTENTS"("A4"."TABLESPACE_ID", "A4"."RELATIVE_FNO", "A4"."HEADER_BLOCK", "A4"."SEGMENT_TYPE_ID", "A4"."BUFFER_POOL_ID", "A4"."SEGMENT_FLAGS", "A4"."SEGMENT_OBJD", "A4"."EXTENTS"), "A4"."EXTENTS")) "EXTENTS", "A4"."INITIAL_EXTENT" "INITIAL_EXTENT", "A4"."NEXT_EXTENT" "NEXT_EXTENT", "A4"."MIN_EXTENTS" "MIN_EXTENTS", "A4"."MAX_EXTENTS" "MAX_EXTENTS", "A4"."MAX_SIZE" "MAX_SIZE", "A4"."RETENTION" "RETENTION", "A4"."MINRETENTION" "MINRETENTION", "A4"."PCT_INCREASE" "PCT_INCREASE", "A4"."FREELISTS" "FREELISTS", "A4"."FREELIST_GROUPS" "FREELIST_GROUPS", "A4"."RELATIVE_FNO" "RELATIVE_FNO", DECODE("A4"."BUFFER_POOL_ID",1,'KEEP',2,'RECYCLE','DEFAULT') "BUFFER_POOL", DECODE("A4"."FLASH_CACHE",1,'KEEP',2, 'NONE','DEFAULT') "FLASH_CACHE",DECODE("A4"."CELL_FLASH_CACHE",1,'KEEP',2,'NONE','DEFAULT') "CELL_FLASH_CACHE" FROM ( (SELECT NVL("A199"."NAME",'SYS') "OWNER", "A198"."NAME" "SEGMENT_NAME",
  187. 187. 192 "A198"."SUBNAME" "PARTITION_NAME", "A196"."OBJECT_TYPE" "SEGMENT_TYPE", "A195"."TYPE#" "SEGMENT_TYPE_ID",DECODE(BIT AND("A195"."SPARE1",2097408),2097152,'SECUREFILE',256,'ASSM','MSSM') "SEGMENT_SUBTYPE", "A197"."TS#" "TABLESPACE_ID", "A197"."NAME" "TABLESPACE_NAME", "A197"."BLOCKSIZE" "BLOCKSIZE", "A194"."FILE#" "HEADER_FILE", "A195"."BLOCK#" "HEADER_BLOCK", "A195"."BLOCKS"*"A197"."BLOCKSIZE" "BYTES", "A195"."BLOCKS" "BLOCKS", "A195"."EXTENTS" "EXTENTS", "A195"."INIEXTS"*"A197"."BLOCKSIZE" "INITIAL_EXTENT", "A195"."EXTSIZE"*"A197"."BLOCKSIZE" "NEXT_EXTENT", "A195"."MINEXTS" "MIN_EXTENTS", "A195"."MAXEXTS" "MAX_EXTENTS",DECODE(BITAND("A195"."SPARE1",4194304),4194304, "A195"."BITMAPRANGES",NULL) "MAX_SIZE",TO_CHAR(DECODE( BITAND("A195"."SPARE1",2097152),2097152, DECODE("A195"."LISTS",0,'NONE',1,'AUTO',2,'MIN',3,'MAX',4,'DEFAULT','INVALID'),NULL)) "RETENTION",DECODE(BITAND("A195"."SPARE1",2097152),2097152, "A195"."GROUPS",NULL) "MINRETENTION",DECODE(BITAND("A197"."FLAGS",3),1,TO_NUMBER(NULL), "A195"."EXTPCT") "PCT_INCREASE",DECODE(BITAND("A197"."FLAGS",32),32, TO_NUMBER(NULL),DECODE("A195"."LISTS",0,1, "A195"."LISTS")) "FREELISTS",DECODE(BITAND("A197"."FLAGS",32),32,TO_NUMBER(NULL),DECODE("A195"."GROUPS",0,1, "A195"."GROUPS")) "FREELIST_GROUPS", "A195"."FILE#" "RELATIVE_FNO",BITAND("A195"."CACHEHINT",3) "BUFFER_POOL_ID", BITAND("A195"."CACHEHINT",12)/4 "FLASH_CACHE",BITAND("A195"."CACHEHINT",48)/16 "CELL_FLASH_CACHE", NVL("A195"."SPARE1",0) "SEGMENT_FLAGS",DECODE(BITAND("A195"."SPARE1",1),1, "A195"."HWMINCR", "A198"."DATAOBJ#") "SEGMENT_OBJD" FROM "SYS"."USER$" "A199", "SYS"."OBJ$" "A198", "SYS"."TS$" "A197", ( (SELECT
  188. 188. 193 DECODE(BITAND("A209"."PROPERTY",8192),8192,'NESTED TABLE','TABLE') "OBJECT_TYPE", 2 "OBJECT_TYPE_ID",5 "SEGMENT_TYPE_ID", "A209"."OBJ#" "OBJECT_ID", "A209"."FILE#" "HEADER_FILE", "A209"."BLOCK#" "HEADER_BLOCK", "A209"."TS#" "TS_NUMBER" FROM "SYS"."TAB$" "A209" WHERE BITAND("A209"."PROPERTY",1024)=0) UNI ON ALL (SELECT 'TABLE PARTITION' "OBJECT_TYPE",19 "OBJECT_TYPE_ID",5 "SEGMENT_TYPE_ID", "A208"."OBJ#" "OBJECT_ID", "A208"."FILE#" "HEADER_FILE", "A208"."BLOCK#" "HEADER_BLOCK", "A208"."TS#" "TS_NUMBER" FROM "SYS"."TABPART$" "A208") UNION ALL (SELECT 'CLUSTER' "OBJECT_TYPE",3 "OBJECT_TYPE_ID",5 "SEGMENT_TYPE_ID", "A207"."OBJ#" "OBJECT_ID", "A207"."FILE#" "HEADER_FILE", "A207"."BLOCK#" "HEADER_BLOCK", "A207"."TS#" "TS_NUMBER" FROM "SYS"."CLU$" "A207") UNION ALL (SELECT DECODE("A206"."TYPE#",8,'LOBINDEX','INDEX') "OBJECT_TYPE",1 "OBJECT_TYPE_ID",6 "SEGMENT_TYPE_ID", "A206"."OBJ#" "OBJECT_ID", "A206"."FILE#" "HEADER_FILE", "A206"."BLOCK#" "HEADER_BLOCK", "A206"."TS#" "TS_NUMBER" FROM "SYS"."IND$" "A206" WHERE "A206"."TYPE#"=1 OR "A206"."TYPE#"=2 OR "A206"."TYPE#"=3 OR "A206"."TYPE#"=4 OR "A206"."TYPE#"=6 OR "A206"."TYPE#"=7 OR "A206"."TYPE#"=8 OR "A206"."TYPE#"=9) UNION ALL (SELECT 'INDEX PARTITION' "OBJECT_TYPE",20 "OBJECT_TYPE_ID",6 "SEGMENT_TYPE_ID", "A205"."OBJ#" "OBJECT_ID", "A205"."FILE#" "HEADER_FILE", "A205"."BLOCK#" "HEADER_BLOCK",
  189. 189. 194 "A205"."TS#" "TS_NUMBER" FROM "SYS"."INDPART$" "A205") UNION ALL (SELECT 'LOBSEGMENT' "OBJECT_TYPE",21 "OBJECT_TYPE_ID",8 "SEGMENT_TYPE_ID", "A204"."LOBJ#" "OBJECT_ID", "A204"."FILE#" "HEADER_FILE", "A204"."BLOCK#" "HEADER_BLOCK", "A204"."TS#" "TS_NUMBER" FROM "SYS"."LOB$" "A204" WHERE BITAND("A204"."PROPERTY",64)=0 OR BITAND("A204"."PROPERTY",128)=128) UNION ALL (SELECT 'TABLE SUBPARTITION' "OBJECT_TYPE",34 "OBJECT_TYPE_ID",5 "SEGMENT_TYPE_ID", "A203"."OBJ#" "OBJECT_ID", "A203"."FILE#" "HEADER_FILE", "A203"."BLOCK#" "HEADER_BLOCK", "A203"."TS#" "TS_NUMBER" FROM "SYS"."TABSUBPART$" "A203") UNION ALL (SELECT 'INDEX SUBPARTITION' "OBJECT_TYPE",35 "OBJECT_TYPE_ID",6 "SEGMENT_TYPE_ID", "A202"."OBJ#" "OBJECT_ID", "A202"."FILE#" "HEADER_FILE", "A202"."BLOCK#" "HEADER_BLOCK", "A202"."TS#" "TS_NUMBER" FROM "SYS"."INDSUBPART$" "A202") UNION ALL (SELECT DECODE("A201"."FRAGTYPE$",'P','LOB PARTITION','LOB SUBPARTITION') "OBJECT_TYPE",DECODE("A201"."FRAGTYPE$",'P',40,41) "OBJECT_TYPE_ID",8 "SEGMENT_TYPE_ID", "A201"."FRAGOBJ#" "OBJECT_ID", "A201"."FILE#" "HEADER_FILE", "A201"."BLOCK#" "HEADER_BLOCK", "A201"."TS#" "TS_NUMBER" FROM "SYS"."LOBFRAG$" "A201")) "A196", "SYS"."SEG$" "A195", "SYS"."FILE$" "A194" WHERE "A195"."FILE#"="A196"."HEADER_FILE" AND "A195"."BLOCK#"="A196"."HEADER_BLOCK" AND "A195"."TS#"="A196"."TS_NUMBER" AND "A195"."TS#"="A197"."TS#" AND "A198"."OBJ#"="A196"."OBJECT_ID" AND "A198"."OWNER#"="A199"."USER#"(+) AND "A195"."TYPE#"="A196"."SEGMENT_TYPE_ID" AND "A198"."TYPE#"="A196"."OBJECT_TYPE_ID" AND "A195"."TS#"="A194"."TS#" AND
  190. 190. 195 "A195"."FILE#"="A194"."RELFILE#") UNION ALL (SELECT NVL("A193"."NAME",'SYS') "OWNER", "A191"."NAME" "SEGMENT_NAME",NULL "PARTITION_NAME", DECODE("A190"."TYPE#",1,'ROLLBACK',10,'TYPE2 UNDO') "SEGMENT_TYPE", "A190"."TYPE#" "SEGMENT_TYPE_ID",NULL "SEGMENT_SUBTYPE", "A192"."TS#" "TABLESPACE_ID", "A192"."NAME" "TABLESPACE_NAME", "A192"."BLOCKSIZE" "BLOCKSIZE", "A189"."FILE#" "HEADER_FILE", "A190"."BLOCK#" "HEADER_BLOCK", "A190"."BLOCKS"*"A192"."BLOCKSIZE" "BYTES", "A190"."BLOCKS" "BLOCKS", "A190"."EXTENTS" "EXTENTS", "A190"."INIEXTS"*"A192"."BLOCKSIZE" "INITIAL_EXTENT", "A190"."EXTSIZE"*"A192"."BLOCKSIZE" "NEXT_EXTENT", "A190"."MINEXTS" "MIN_EXTENTS", "A190"."MAXEXTS" "MAX_EXTENTS",DECODE(BITAND("A190"."SPARE1",4194304),4194304, "A190"."BITMAPRANGES",NULL) "MAX_SIZE",NULL "RETENTION",NULL "MINRETENTION", "A190"."EXTPCT" "PCT_INCREASE",DECODE(BITAND("A192"."FLAGS",32),32,TO_NUMBER(NULL),DECODE("A190"."LISTS",0,1, "A190"."LISTS")) "FREELISTS",DECODE(BITAND("A192"."FLAGS",32),32,TO_NUMBER(NULL), DECODE("A190"."GROUPS",0,1,"A190"."GROUPS")) "FREELIST_GROUPS", "A190"."FILE#" "RELATIVE_FNO",BITAND("A190"."CACHEHINT",3) "BUFFER_POOL_ID",BITAND("A190"."CACHEHINT",12)/4 "FLASH_CACHE", BITAND("A190"."CACHEHINT",48)/16 "CELL_FLASH_CACHE",NVL("A190"."SPARE1",0) "SEGMENT_FLAGS", "A191"."US#" "SEGMENT_OBJD" FROM "SYS"."USER$" "A193","SYS"."TS$" "A192", "SYS"."UNDO$" "A191", "SYS"."SEG$" "A190", "SYS"."FILE$" "A189" WHERE "A190"."FILE#"="A191"."FILE#" AND "A190"."BLOCK#"="A191"."BLOCK#" AND "A190"."TS#"="A191"."TS#" AND "A190"."TS#"="A192"."TS#" AND "A190"."USER#"="A193"."USER#"(+) AND ("A190"."TYPE#"=1 OR "A190"."TYPE#"=10) AND "A191"."STATUS$"<>1 AND
  191. 191. 196 "A191"."TS#"="A189"."TS#" AND "A191"."FILE#"="A189"."RELFILE#") UNION ALL (SELECT NVL("A188"."NAME",'SYS') "OWNER", TO_CHAR("A185"."FILE#")||'.'||TO_CHAR("A186"."BLOCK#") "SEGMENT_NAME",NULL "PARTITION_NAME", DECODE("A186"."TYPE#",2,'DEFERRED ROLLBACK',3, 'TEMPORARY',4,'CACHE',9,'SPACE HEADER','UNDEFINED') "SEGMENT_TYPE", "A186"."TYPE#" "SEGMENT_TYPE_ID",NULL "SEGMENT_SUBTYPE", "A187"."TS#" "TABLESPACE_ID", "A187"."NAME" "TABLESPACE_NAME", "A187"."BLOCKSIZE" "BLOCKSIZE", "A185"."FILE#" "HEADER_FILE", "A186"."BLOCK#" "HEADER_BLOCK", "A186"."BLOCKS"*"A187"."BLOCKSIZE" "BYTES", "A186"."BLOCKS" "BLOCKS", "A186"."EXTENTS" "EXTENTS", "A186"."INIEXTS"*"A187"."BLOCKSIZE" "INITIAL_EXTENT", "A186"."EXTSIZE"*"A187"."BLOCKSIZE" "NEXT_EXTENT", "A186"."MINEXTS" "MIN_EXTENTS", "A186"."MAXEXTS" "MAX_EXTENTS",DECODE(BITAND("A186"."SPARE1",4194304),4194304, "A186"."BITMAPRANGES",NULL) "MAX_SIZE",NULL "RETENTION",NULL "MINRETENTION",DECODE(BITAND("A187"."FLAGS",3),1,TO_NUMBER(NULL), "A186"."EXTPCT") "PCT_INCREASE",DECODE(BITAND("A187"."FLAGS",32),32,TO_NUMBER(NULL),DECODE("A186"."LISTS",0,1, "A186"."LISTS")) "FREELISTS",DECODE(BITAND("A187"."FLAGS",32),32,TO_NUMBER(NULL),DECODE("A186"."GROUPS",0,1, "A186"."GROUPS")) "FREELIST_GROUPS", "A186"."FILE#" "RELATIVE_FNO",BITAND("A186"."CACHEHINT",3) "BUFFER_POOL_ID",BITAND("A186"."CACHEHINT",12)/4 "FLASH_CACHE",BITAND("A186"."CACHEHINT",48)/16 "CELL_FLASH_CACHE",NVL("A186"."SPARE1",0) "SEGMENT_FLAGS", "A186"."HWMINCR" "SEGMENT_OBJD" FROM "SYS"."USER$" "A188", "SYS"."TS$" "A187", "SYS"."SEG$" "A186", "SYS"."FILE$" "A185" WHERE "A186"."TS#"="A187"."TS#" AND "A186"."USER#"="A188"."USER#"(+) AND "A186"."TYPE#"<>1 AND "A186"."TYPE#"<>5 AND
  192. 192. 197 "A186"."TYPE#"<>6 AND "A186"."TYPE#"<>8 AND "A186"."TYPE#"<>10 AND "A186"."TYPE#"<>11 AND "A186"."TS#"="A185"."TS#" AND "A186"."FILE#"="A185"."RELFILE#") UNION ALL (SELECT NVL("A184"."NAME",'SYS') "OWNER",'HEATMAP' "SEGMENT_NAME", NULL "PARTITION_NAME",'SYSTEM STATISTICS' "SEGMENT_TYPE", "A182"."TYPE#" "SEGMENT_TYPE_ID",NULL "SEGMENT_SUBTYPE", "A183"."TS#" "TABLESPACE_ID", "A183"."NAME" "TABLESPACE_NAME", "A183"."BLO CKSIZE" "BLOCKSIZE", "A181"."FILE#" "HEADER_FILE", "A182"."BLOCK#" "HEADER_BLOCK", "A182"."BLOCKS"*"A183"."BLOCKSIZE" "BYTES", "A182"."BLOCKS" "BLOCKS", "A182"."EXTENTS" "EXTENTS", "A182"."INIEXTS"*"A183"."BLOCKSIZE" "INITIAL_EXTENT", "A182"."EXTSIZE"*"A183"."BLOCKSIZE" "NEXT_EXTENT", "A182"."MINEXTS" "MIN_EXTENTS", "A182"."MAXEXTS" "MAX_EXTENTS",DECODE(BITAND("A182"."SPARE1",4194304),4194304, "A182"."BITMAPRANGES",NULL) "MAX_SIZE",NULL "RETENTION",NULL "MINRETENTION",DECODE(BITAND("A183"."FLAGS",3),1,TO_NUMBER(NULL), "A182"."EXTPCT") "PCT_INCREASE",DECODE(BITAND("A183"."FLAGS",32),32,TO_NUMBER(NULL),DEC ODE("A182"."LISTS",0,1, "A182"."LISTS")) "FREELISTS",DECODE(BITAND("A183"."FLAGS",32),32,TO_NUMBER(NULL),DECODE("A182"."GROUPS",0,1, "A182"."GROUPS")) "FREELIST_GROUPS", "A182"."FILE#" "RELATIVE_FNO",BITAND("A182"."CACHEHINT",3) "BUFFER_POOL_ID", BITAND("A182"."CACHEHINT",12)/4 "FLASH_CACHE",BITAND("A18 2"."CACHEHINT",48)/16 "CELL_FLASH_CACHE",NVL("A182"."SPARE1",0) "SEGMENT_FLAGS", "A182"."HWMINCR" "SEGMENT_OBJD" FROM "SYS"."USER$" "A184",
  193. 193. 198 "SYS"."TS$" "A183", "SYS"."SEG$" "A182", "SYS"."FILE$" "A181" WHERE "A182"."TS#"="A183"."TS#" AND "A182"."USER#"="A184"."USER#"(+) AND "A182"."TYPE#"=11 AND "A182"."TS#"="A181"."TS#" AND "A182"."FILE#"="A181"."RELFILE#")) "A4") "A3", (SELECT "A5"."NAME" "OWNER", "A6"."NAME" "OBJECT_NAME", "A6"."SUBNAME" "SUBOBJECT_NAME", "A6"."OBJ#" "OBJECT_ID", "A6"."DATAOBJ#" "DATA_OBJECT_ID",DECODE("A6"."TYPE#",0,'NEXT OBJECT',1,'INDEX', 2,'TABLE',3,'CLUSTER',4,'VIEW',5,'SYNONYM ',6,'SEQUENCE',7,'PROCEDURE',8,'FUNCTION',9,'PACKAGE',11,'PACKAGE BODY',12, 'TRIGGER',13,'TYPE',14,'TYPE BODY',19,'TABLE PARTITION',20,'INDEX PARTITION', 21,'LOB',22,'LIBRARY',23,'DIRECTORY',24,'QUEUE',28,'JAVA SOURCE',29,'JAVA CLASS',30, 'JAVA RESOURCE',32,'INDEXTYPE',33,'OPERATOR',34, 'TABLE SUBPARTITION',35,'INDEX SUBPARTITION',40,'LOB PARTITION',41,'LOB SUBPARTITION',42 ,NVL( (SELECT 'REWRITE EQUIVALENCE' "'REWRITEEQUIVALENCE'" FROM SYS."SUM$" "A52" WHERE "A52"."OBJ#"="A6"."OBJ#" AND BITAND("A52"."XPFLAGS",8388608)=8388608),'MATERIALIZED VIEW'),43,'DIMENSION', 44,'CONTEXT',46,'RULE SET',47,'RESOURCE PLAN',48,'CONSUMER GROUP',55,'XML SCHEMA',56,'JAVA DATA',57,'EDITION',59,'RULE', 60,'CAPTURE',61,'APPLY',62,'EVALUATION CONTEXT',66,'JOB',67,'PROGRAM',68,'JOB CLASS',69, 'WINDOW',72,'SCHEDULER GROUP',74,'SCHEDULE',79,'CHAIN',81,'FILE GROUP',82,'MINING MODEL',87,'ASSEMBLY',90,'CREDENTIAL',92,'CUBE DIMENSION',93,'CUBE',94,'MEASURE FOLDER',95,'CUBE BUILD PROCESS',100,'FILE WATCHER', 101,'DESTINATION',114,'SQL TRANSLATION PROFILE',115,'UNIFIED AUDIT POLICY','UNDEFINED') "OBJECT_TYPE", "A6"."CTIME" "CREATED", "A6"."MTIME" "LAST_DDL_TIME",TO_CHAR("A6"."STIME",'YYYY-MM-DD:HH24:MI:SS') "TIMESTAMP",DEC ODE("A6"."STATUS",0,'N/A',1,'VALID','INVALID') "STATUS",DECODE(BITAND("A6"."FLAGS",2),0,'N',2,'Y','N') "TEMPORARY",DECODE(BITAND("A6"."FLAGS",4),0,'N',4,'Y','N') "GENERATED",DECODE(BITAND("A6"."FLAGS",16),0,'N',16,'Y','N') "SECONDARY", "A6"."NAMESPACE" "NAMESPACE", "A6"."DEFINING_EDITION" "EDITION_NAM E",DECODE(BITAND("A6"."FLAGS",196608),65536,'METADATA LINK',131072,'OBJECT LINK','NONE') "SHARING", CASE WHEN ("A6"."TYPE#"=4 OR "A6"."TYPE#"=5 OR
  194. 194. 16 ... 199 more pages
  195. 195. reading a single table 200
  196. 196. should I use an index ? 201
  197. 197. full scan versus index 202
  198. 198. 203 SQL> select * 2 from STUDENT 3 where gender = 'W';
  199. 199. full scan (dba_extents) File 1, Block 271, 512 blocks File 2, Block 234, 256 blocks etc
  200. 200. indexed access W, File 1, Block 37, Row 4 W, File 1, Block 437, Row 11 Sue Jane POOL_IX (POOL_TYPE) STUDENT
  201. 201. what will a full scan cost ? 206
  202. 202. 207 SQL> select blocks 2 from dba_tables 3 where owner = 'SCOTT' 4 and table_name = 'STUDENT'; BLOCKS ---------- 9083
  203. 203. dbms_space 208
  204. 204. 209 SQL> select value 2 from v$parameter 3 where name = 'db_file_multiblock_read_count'; VALUE --------------- 128
  205. 205. IO cost blocks / blocks at a time 210
  206. 206. adjusted downwards 211
  207. 207. adj = 1.6765 x orig0.6581 212 Ack: Wolfgang Brietling, 2001
  208. 208. 128 213 41
  209. 209. 214 SQL> set autotrace traceonly explain SQL> select /*+ no_cpu_costing */ * from STUDENT; ----------------------------------------------------- | Id | Operation | Name | Rows | Cost | ----------------------------------------------------- | 0 | SELECT STATEMENT | | 531K| 224 | | 1 | TABLE ACCESS FULL| STUDENT | 531K| 224 | ----------------------------------------------------- 9083 / 41 = 221
  210. 210. 215 SQL> set autotrace traceonly explain SQL> select /*+ no_cpu_costing */ * from STUDENT; ----------------------------------------------------- | Id | Operation | Name | Rows | Cost | ----------------------------------------------------- | 0 | SELECT STATEMENT | | 531K| 224 | | 1 | TABLE ACCESS FULL| STUDENT | 531K| 224 | ----------------------------------------------------- 9083 / 41 = 221
  211. 211. "digest" the rows 216
  212. 212. 217
  213. 213. 218 SQL> set autotrace traceonly explain SQL> select * from STUDENT; ----------------------------------------------------- | Id | Operation | Name | Rows | Cost | ----------------------------------------------------- | 0 | SELECT STATEMENT | | 531K| 1586 | | 1 | TABLE ACCESS FULL| STUDENT | 531K| 1586 | -----------------------------------------------------
  214. 214. what will a index scan cost ? 219
  215. 215. a few blocks + 220
  216. 216. 221 SQL> select AVG_LEAF_BLOCKS_PER_KEY 2 from USER_INDEXES 3 where INDEX_NAME = 'STUDENT_IX' AVG_LEAF_BLOCKS_PER_KEY ----------------------- 6
  217. 217. approximation 222
  218. 218. the easiest way
  219. 219. run a few... valid use of hints
  220. 220. understanding joins
  221. 221. nested loops hash sort merge index join and-equal btree-bitmap conversion bitmap join
  222. 222. other complexities bloom filters parallel
  223. 223. nested loop
  224. 224. "for each row in outer, check for row in inner"
  225. 225. for (i=1; i<100; i++) for (j=1; j<100; j++) for (k=1; k<100; k++) ... ...
  226. 226. demo
  227. 227. cost
  228. 228. effort = L1 + M * L2 = cost to Lookup rows in outer table number of rows Matching criteria in outer table cost of Lookup matching row in inner table
  229. 229. High M ... no good effort = L1 + M * L2 =
  230. 230. High L2 ... no good effort = L1 + M * L2 =
  231. 231. High L1 ... no good maybe effort = L1 + M * L2
  232. 232. sort merge
  233. 233. demo
  234. 234. merge
  235. 235. cost
  236. 236. effort = S1 + S2 + M sort table 1 (hold result) sort table 2 (hold result) merge results (not held*)
  237. 237. risks
  238. 238. RAM SQL> select value * 0.05 / 1024 sort_kb 2 from v$parameter 3 where name = 'pga_aggregate_target'; SORT_KB ---------- 2457.6
  239. 239. single pass
  240. 240. really big sorts
  241. 241. multipass sorts
  242. 242. detection
  243. 243. SQL> select * from v$mystat / v$sesstat / v$sysstat 2 where name like 'work%'; NAME VALUE ----------------------------------- ---------- workarea executions - optimal 12 workarea executions - onepass 0 workarea executions - multipass 0
  244. 244. why sort merge ?
  245. 245. non-equality joins where t1.name > t2.name
  246. 246. hash joins
  247. 247. 7.3
  248. 248. 260 SQL> select value 2 from v$parameter 3 where name = 'hash_join_enabled'; VALUE ---------------------- true
  249. 249. 261
  250. 250. "best" join 262
  251. 251. divide and conquer 263
  252. 252. demo 264
  253. 253. 265
  254. 254. 266
  255. 255. much larger hash 267
  256. 256. = and != only 268
  257. 257. nested loop good selectivity into each table small numbers of (result) rows first row fast 269
  258. 258. hash join the "best" join (theory) 270
  259. 259. sort merge rarely seen partial joins 271
  260. 260. 272 back to our problem SQL
  261. 261. SQL> select e.department_id, sum(salary) 2 from emp e, 3 job_hist j 4 where e.employee_id = j.employee_id 5 and extract(year from e.hire_date) > 1985 6 and j.end_date > j.start_date + 1 7 and j.start_date >= e.hire_date 8 group by e.department_id 273
  262. 262. 274 v$sql_plan
  263. 263. ----------------------------------------------------------------------------- | 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)| ----------------------------------------------------------------------------- 275
  264. 264. 276 now what ?
  265. 265. "where does it hurt ?" 277
  266. 266. 278
  267. 267. 279 where in the plan ...
  268. 268. SQL> select 2 DBMS_SQLTUNE.REPORT_SQL_MONITOR( 3 sql_id=>'d3ncuxj7629bf', 4 report_level=>'ALL', 5 type=>'HTML') as report 6 from dual; 280
  269. 269. options 284 rewrite the sql hints add indexes remove indexes
  270. 270. rewrite the sql 285
  271. 271. ideally ... simply 286
  272. 272. 287 dynamic sampling
  273. 273. 288 cardinality is everything 288
  274. 274. 289
  275. 275. 290
  276. 276. 291 same with Oracle 291
  277. 277. 292 actual versus estimate 292
  278. 278. 293 SQL> select /*+ GATHER_PLAN_STATISTICS */ count(*) 2 from VEHICLES 3 where MAKE = 'FORD' 4 and MODEL = 'FOCUS'; COUNT(*) ---------- 214468 293
  279. 279. 294 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| VEHICLES| 1 | 220K| 214K| ----------------------------------------------------------------- 294
  280. 280. 295 295 if the estimate is wrong
  281. 281. 296 296 try dynamic sampling
  282. 282. 297 SQL> create table TOUGH_DATA as 2 select 3 rownum pk, 4 dbms_random.string('U',10) str 5 from dual 6 connect by level < 1000000 7 / Table created. SQL> exec dbms_stats.gather_table_stats( user,'TOUGH_DATA')
  283. 283. 298 SQL> select count(*) 2 from TOUGH_DATA 3 where str like '%XX' 4 / COUNT(*) ---------- 1452 hard
  284. 284. 299 SQL> select count(*) 2 from TOUGH_DATA 3 where str like '%XX' 4 / ------------------------------------------------- | Id | Operation | Name | Rows | ------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 1 | SORT AGGREGATE | | 1 | |* 2 | TABLE ACCESS FULL| TOUGH_DATA | 50000 | ------------------------------------------------- 5% assumption
  285. 285. 300 SQL> select /*+ dynamic_sampling(t 2) */ count(*) 2 from TOUGH_DATA t 3 where str like '%XX' 4 / ------------------------------------------------- | Id | Operation | Name | Rows | ------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 1 | SORT AGGREGATE | | 1 | |* 2 | TABLE ACCESS FULL| TOUGH_DATA | 1252 | -------------------------------------------------
  286. 286. more drastic measures 301
  287. 287. use hints 302
  288. 288. 303 "optimizer hints should only be used with extreme care" Maria Colgan, Oct 2012 Optimizer product manager
  289. 289. awesome hints 304
  290. 290. 305 gather_plan_statistics dynamic_sampling monitor qb_name
  291. 291. query blocks 306
  292. 292. C# PL/SQL 307
  293. 293. no comments 308
  294. 294. 309
  295. 295. "C# is self-documenting" 310
  296. 296. for (int i = 0; i < w.Count; ++i) { if (w[i].v > 0 && w[i].p > mddh) { m = Math.Max(m, w[i].d); } } for (int i = 0; i < w.Count; ++i) { if (w[i].v > 0 && w[i].p > mddh) { w[i].d = m / w[i].d; s += w[i].d; } } 311
  297. 297. query blocks = self- documenting SQL 312
  298. 298. select emp.* from emp, ( select trunc(hiredate,'YYYY'), max(empno) empno from emp where empno > 0 group by trunc(hiredate,'YYYY') ) x, ( select deptno, avg(sal) from emp group by deptno ) y where x.empno = emp.empno and y.deptno = emp.deptno 313
  299. 299. Id | Operation | Name | ----------------------------------------------| 0 | SELECT STATEMENT | | 1 | HASH JOIN | | 2 | TABLE ACCESS BY INDEX ROWID | EMP | 3 | NESTED LOOPS | | 4 | VIEW | | 5 | SORT GROUP BY | | 6 | TABLE ACCESS BY INDEX ROWID| EMP | 7 | INDEX FULL SCAN | E2 | 8 | INDEX RANGE SCAN | E1 | 9 | VIEW | | 10 | SORT GROUP BY | | 11 | TABLE ACCESS BY INDEX ROWID | EMP | 12 | INDEX RANGE SCAN | E2 | 314
  300. 300. select emp.* from emp, ( select /*+ QB_NAME(YR_HIRE) */ trunc(hiredate,'YYYY'), max(empno) empno from emp where empno > 0 group by trunc(hiredate,'YYYY') ) x, ( select /*+ QB_NAME(AV_SAL) */ deptno, avg(sal) from emp group by deptno ) y where x.empno = emp.empno and y.deptno = emp.deptno 315
  301. 301. Id | Operation | Name | Query Block ----------------------------------------------|-------------- 0 | SELECT STATEMENT | | 1 | HASH JOIN | | 2 | TABLE ACCESS BY INDEX ROWID | EMP | 3 | NESTED LOOPS | | 4 | VIEW | | 5 | SORT GROUP BY | | 6 | TABLE ACCESS BY INDEX ROWID| EMP | 7 | INDEX FULL SCAN | E2 | 8 | INDEX RANGE SCAN | E1 | 9 | VIEW | | 10 | SORT GROUP BY | | 11 | TABLE ACCESS BY INDEX ROWID | EMP | 12 | INDEX RANGE SCAN | E2 | SEL$1 SEL$1 AV_SAL AV_SAL AV_SAL AV_SAL SEL$1 YR_HIRE YR_HIRE YR_HIRE YR_HIRE 316
  302. 302. assist with other hints 317
  303. 303. select /*+ QB_NAME(top) INDEX(@yr_hire emp (empno)) FULL(@av_sal emp) */ emp.* from emp, ( select /*+ QB_NAME(YR_HIRE) */ trunc(hiredate,'YYYY'), max(empno) empno from emp where empno > 0 group by trunc(hiredate,'YYYY') ) x, ( select /*+ QB_NAME(AV_SAL) */ deptno, avg(sal) from emp group by deptno ) y where x.empno = emp.empno and y.deptno = emp.deptno 318
  304. 304. sidebar 319
  305. 305. 320 select /*+ QB_NAME(top) INDEX(@yr_hire emp (empno)) FULL(@av_sal emp) */ INDEX(emp emp_ix)
  306. 306. cool hints 321
  307. 307. 322 first_rows_n all_rows leading cardinality statement_queueing opt_param
  308. 308. assisting optimizer 323
  309. 309. dangerous hints 324
  310. 310. everything else... 325
  311. 311. 326 full index use_hash use_nl etc
  312. 312. suppressing the optimizer 327
  313. 313. undocumented hints 328
  314. 314. 329 selectivity no_trigger
  315. 315. an invalid hint 330
  316. 316. is a comment 331
  317. 317. 332 SQL> select /*+ INDEX(accounts_pk) */ 2 from ACCOUNTS 3 where ... SQL> select /*+ INDEX(a) */ 2 from ACCOUNTS 3 where ... SQL> select /*+ INDEX(scott.accounts) */ 2 from SCOTT.ACCOUNTS 3 where ... SQL> select /* INDEX(A) */ 2 from SCOTT.ACCOUNTS A 3 where ...
  318. 318. no error raised ! 333
  319. 319. even if it IS valid ... 334
  320. 320. ... the (in)famous ignore issue 335
  321. 321. 336 SQL> select * 2 from emp e, 3 dept d 4 where e.deptno = d.deptno 5 and d.dname = 'SALES'; -------------------------------------------------------- | Id | Operation | Name | Rows | -------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | | 1 | MERGE JOIN | | 5 | |* 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | | 3 | INDEX FULL SCAN | PK_DEPT | 4 | |* 4 | SORT JOIN | | 14 | | 5 | TABLE ACCESS FULL | EMP | 14 | --------------------------------------------------------
  322. 322. 337 "I want a hash join"
  323. 323. 338 SQL> select /*+ use_hash(d) */ * 2 from emp e, 3 dept d 4 where e.deptno = d.deptno 5 and d.dname = 'SALES'; -------------------------------------------------------- | Id | Operation | Name | Rows | -------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | | 1 | MERGE JOIN | | 5 | |* 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | | 3 | INDEX FULL SCAN | PK_DEPT | 4 | |* 4 | SORT JOIN | | 14 | | 5 | TABLE ACCESS FULL | EMP | 14 | --------------------------------------------------------
  324. 324. 339 /*+ use_hash(d) */ if joining into "d"... use a hash join
  325. 325. we're not... 340
  326. 326. 341 -------------------------------------------------------- | Id | Operation | Name | Rows | -------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | | 1 | MERGE JOIN | | 5 | |* 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | | 3 | INDEX FULL SCAN | PK_DEPT | 4 | |* 4 | SORT JOIN | | 14 | | 5 | TABLE ACCESS FULL | EMP | 14 | --------------------------------------------------------
  327. 327. 342 if joining into "d"... we must be starting with "e"
  328. 328. 343 SQL> select /*+ leading(e) use_hash(d) */ * 2 from emp e, 3 dept d 4 where e.deptno = d.deptno 5 and d.dname = 'SALES'; --------------------------------------------------- | Id | Operation | Name | Rows | Bytes | --------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 285 | |* 1 | HASH JOIN | | 5 | 285 | | 2 | TABLE ACCESS FULL| EMP | 14 | 518 | |* 3 | TABLE ACCESS FULL| DEPT | 1 | 20 | ---------------------------------------------------
  329. 329. not enough hints 344
  330. 330. 345 "hints are like violence… if they do not work, use more"
  331. 331. 346 SQL> select /*+ leading(e d b) use_hash(d) use_hash(b) */ * 2 from emp e, 3 dept d, 4 bonus b 5 where e.deptno = d.deptno 6 and d.dname = 'SALES' 7 and e.ename = b.ename; --------------------------------------------- | Id | Operation | Name | Rows | --------------------------------------------- | 0 | SELECT STATEMENT | | 1 | |* 1 | HASH JOIN | | 1 | |* 2 | HASH JOIN | | 5 | | 3 | TABLE ACCESS FULL| EMP | 14 | |* 4 | TABLE ACCESS FULL| DEPT | 1 | | 5 | TABLE ACCESS FULL | BONUS | 1 | ---------------------------------------------
  332. 332. 347 SQL> select /*+ leading(e d b) use_hash(d) use_hash(b) */ * 2 from emp e, 3 dept d, 4 bonus b 5 where e.deptno = d.deptno 6 and d.dname = 'SALES' 7 and e.ename = b.ename; --------------------------------------------- | Id | Operation | Name | Rows | --------------------------------------------- | 0 | SELECT STATEMENT | | 1 | |* 1 | HASH JOIN | | 1 | | 2 | TABLE ACCESS FULL | BONUS | 1 | |* 3 | HASH JOIN | | 5 | | 4 | TABLE ACCESS FULL| EMP | 14 | |* 5 | TABLE ACCESS FULL| DEPT | 1 | ---------------------------------------------
  333. 333. 348 --------------------------------------------- | Id | Operation | Name | Rows | --------------------------------------------- | 0 | SELECT STATEMENT | | 1 | |* 1 | HASH JOIN | | 1 | |* 2 | HASH JOIN | | 5 | | 3 | TABLE ACCESS FULL| EMP | 14 | |* 4 | TABLE ACCESS FULL| DEPT | 1 | | 5 | TABLE ACCESS FULL | BONUS | 1 | --------------------------------------------- --------------------------------------------- | Id | Operation | Name | Rows | --------------------------------------------- | 0 | SELECT STATEMENT | | 1 | |* 1 | HASH JOIN | | 1 | | 2 | TABLE ACCESS FULL | BONUS | 1 | |* 3 | HASH JOIN | | 5 | | 4 | TABLE ACCESS FULL| EMP | 14 | |* 5 | TABLE ACCESS FULL| DEPT | 1 | ---------------------------------------------
  334. 334. join inputs 349
  335. 335. 350 SQL> select /*+ leading(e d b) 2 use_hash(d) 3 use_hash(b) 4 no_swap_join_inputs(b) 5 */ 6 * 7 from emp e, 8 dept d, 9 bonus b 10 where e.deptno = d.deptno 11 and d.dname = 'SALES' 12 and e.ename = b.ename;
  336. 336. problem ... 351
  337. 337. 352 /*+ no_swap_join_inputs (b) */
  338. 338. option 1 353
  339. 339. fully specify hints 354
  340. 340. 355 SQL> SELECT * 2 from table(dbms_xplan.display(.... , format=>'typical +OUTLINE)) /*+ BEGIN_OUTLINE_DATA USE_HASH(@"SEL$1" "B"@"SEL$1") USE_HASH(@"SEL$1" "D"@"SEL$1") LEADING(@"SEL$1" "E"@"SEL$1" "D"@"SEL$1" "B"@"SEL$1") FULL(@"SEL$1" "B"@"SEL$1") FULL(@"SEL$1" "D"@"SEL$1") FULL(@"SEL$1" "E"@"SEL$1") OUTLINE_LEAF(@"SEL$1") ALL_ROWS DB_VERSION('11.2.0.2') OPTIMIZER_FEATURES_ENABLE('11.2.0.2') IGNORE_OPTIM_EMBEDDED_HINTS END_OUTLINE_DATA */ Ack: M.Colgan swap still possible !
  341. 341. option 2 356
  342. 342. sql baseline 357
  343. 343. just hints … better in 12c 358
  344. 344. add / remove indexes 359
  345. 345. side effects 360
  346. 346. 361 structural change
  347. 347. "an index will fix it..." 362
  348. 348. 363 SQL> select * 2 from SALES 3 where SALES_DATE > ...
  349. 349. 364
  350. 350. 365 SQL> create index SALES_IX 2 on SALES( SALES_DATE ); Index created.
  351. 351. 366 SQL> explain plan for 2 select * from SALES 3 where sales_date > ...; -------------------------------------------------------- | Id | Operation | Name | Rows | -------------------------------------------------------- | 0 | SELECT STATEMENT | | 950 | | 1 | TABLE ACCESS BY INDEX ROWID| SALES | 950 | |* 2 | INDEX RANGE SCAN | SALES_IX | 950 | --------------------------------------------------------
  352. 352. 367
  353. 353. 368
  354. 354. 369 your query
  355. 355. 370 everyone elses queries
  356. 356. 371 real example
  357. 357. 372 SQL> create table T 2 as select * from all_objects; Table created. SQL> create index OBJ_IX on T ( OBJECT_ID); Index created. SQL> analyze table T estimate statistics; Table analyzed.
  358. 358. 373 SQL> set autotrace traceonly explain SQL> select * from T 2 where OWNER = 'SCOTT' 3 and created > sysdate - 1 4 / --------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| --------------------------------------------------------------- | 0 | SELECT STATEMENT | | 6 | 546 | 281 (1)| |* 1 | TABLE ACCESS FULL| T | 6 | 546 | 281 (1)| ---------------------------------------------------------------
  359. 359. 374 “Can I index OWNER..”
  360. 360. 375 SQL> create index NEW_IX on T ( owner); Index created. SQL> select * from T 2 where OWNER = 'SCOTT' 3 and created > sysdate - 1; --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 6 | 546 | 122 (0)| |* 1 | TABLE ACCESS BY INDEX ROWID| T | 6 | 546 | 122 (0)| |* 2 | INDEX RANGE SCAN | NEW_IX | 4107 | | 10 (0)| ---------------------------------------------------------------------------
  361. 361. 376 existing code ?
  362. 362. 377 before the new index
  363. 363. 378 SQL> set autotrace traceonly explain SQL> select * from T 2 where OWNER = 'SYS' 3 and OBJECT_ID between 10 and 8000 4 / --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 462 | 42042 | 143 (0)| |* 1 | TABLE ACCESS BY INDEX ROWID| T | 462 | 42042 | 143 (0)| |* 2 | INDEX RANGE SCAN | OBJ_IX | 7851 | | 20 (0)| ---------------------------------------------------------------------------
  364. 364. 379 SQL> set autotrace traceonly stat SQL> select * from T 2 where owner = 'SYS' 3 and object_id between 10 and 8000 4 / 4967 rows selected. Statistics ----------------------------------------------------- 0 recursive calls 0 db block gets 784 consistent gets 15 physical reads
  365. 365. 380 after the new index
  366. 366. 381 SQL> select * from T 2 where owner = 'SYS' 3 and object_id between 10 and 8000 4 / --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 462 | 42042 | 122 (0)| |* 1 | TABLE ACCESS BY INDEX ROWID| T | 462 | 42042 | 122 (0)| |* 2 | INDEX RANGE SCAN | NEW_IX | 4105 | | 10 (0)| --------------------------------------------------------------------------- changed !
  367. 367. 382 SQL> set autotrace traceonly stat SQL> select * from T 2 where owner = 'SYS' 3 and object_id between 10 and 8000 4 / 4967 rows selected. Statistics ------------------------------------------------------ 0 recursive calls 0 db block gets 1522 consistent gets 62 physical reads
  368. 368. 383 invisible indexesconsider
  369. 369. 384 SQL> alter index OWN_IX invisible; Index altered.
  370. 370. 385 SQL> alter session set 2 optimizer_use_invisible_indexes = true; Session altered. SQL> [MY QUERY] SQL> alter session set 2 optimizer_use_invisible_indexes = false; Session altered.
  371. 371. wrap up 386
  372. 372. if you are tuning SQL ... 387 ... you are failing
  373. 373. tuning the user experience 388
  374. 374. 389 find stop side effects cure
  375. 375. 390
  376. 376. ORA-03113 connormcdonald.wordpress.com

×