Connor McDonald Partitioning

2,017 views

Published on

A look at the partitioning facilities all the way up 11g

Published in: Technology
1 Comment
0 Likes
Statistics
Notes
  • Many thanks for all the helpful information.

    Atish
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Be the first to like this

No Downloads
Views
Total views
2,017
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
77
Comments
1
Likes
0
Embeds 0
No embeds

No notes for slide

Connor McDonald Partitioning

  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 ? ...now 7
  8. 8. version 8.0 8
  9. 9. 9
  10. 10. 10
  11. 11. a personal history 11
  12. 12. 80's 12
  13. 13. 13
  14. 14. 14
  15. 15. Walker Interactive 15
  16. 16. Jeff Walker... 16
  17. 17. 20G 17
  18. 18. $200 per gigabyte per month 19
  19. 19. Storage is expensive 20
  20. 20. Archive 21
  21. 21. 22
  22. 22. 90's 23
  23. 23. 24
  24. 24. JBOD 25
  25. 25. Storage is cheap ! 26
  26. 26. Archive 27
  27. 27. Archive 28
  28. 28. 1992 1996 1999
  29. 29. 30
  30. 30. 00's 31
  31. 31. disk is even cheaper.... 32
  32. 32. 33
  33. 33. ....but 34
  34. 34. keep everything ! 36
  35. 35. JBOD 37
  36. 36. 38
  37. 37. HBA Infiniband Filer Cache Fibre Channel etc 39
  38. 38. Storage is cheap ! 40
  39. 39. Storage Storage is is expensive cheap ! 41
  40. 40. CEO 42
  41. 41. brings us to today... 43
  42. 42. ILM 44
  43. 43. Information Lifecycle Management 45
  44. 44. keep everything .... cheaply 46
  45. 45. put the new stuff on good storage keep everything .... cheaply put the old stuff on crappy storage 47
  46. 46. split stuff up 48
  47. 47. 49
  48. 48. basics 50
  49. 49. range partitioning since 8.0 51
  50. 50. SALES 2009 2010 2011 2012 52
  51. 51. provocative statement 53
  52. 52. "all applications are (time) windows on data" http://thehelsinkideclaration.blogspot.com/ 54
  53. 53. corollary: everyone can benefit from range partitions 55
  54. 54. time the most common 56
  55. 55. SQL> create table DEMO 2 ( tstamp timestamp(6) not null, 3 empno number(10) not null, 4 ename varchar2(10) not null, 5 deptno varchar2(10) not null 6 ) 7 PARTITION BY RANGE (TSTAMP) 8 ( 9 PARTITION p01 VALUES LESS THAN 10 (TIMESTAMP' 2010-01-01 00:00:00'), 11 PARTITION p02 VALUES LESS THAN 12 (TIMESTAMP' 2010-02-01 00:00:00'), 13 PARTITION p03 VALUES LESS THAN 14 (TIMESTAMP' 2010-03-01 00:00:00'), ... ... 25 PARTITION p13 VALUES LESS THAN 26 (TIMESTAMP' 2011-01-01 00:00:00') 27 ); Table created. 57
  56. 56. SQL> select partition_name pname, 2 partition_position pos, 3 high_value 4 from USER_TAB_PARTITIONS 5 where table_name = 'DEMO'; PNAME POS HIGH_VALUE ----- ---------- ------------------------------- P01 1 TIMESTAMP' 2010-01-01 00:00:00' P02 2 TIMESTAMP' 2010-02-01 00:00:00' P03 3 TIMESTAMP' 2010-03-01 00:00:00' P04 4 TIMESTAMP' 2010-04-01 00:00:00' P05 5 TIMESTAMP' 2010-05-01 00:00:00' P06 6 TIMESTAMP' 2010-06-01 00:00:00' P07 7 TIMESTAMP' 2010-07-01 00:00:00' P08 8 TIMESTAMP' 2010-08-01 00:00:00' P09 9 TIMESTAMP' 2010-09-01 00:00:00' P10 10 TIMESTAMP' 2010-10-01 00:00:00' P11 11 TIMESTAMP' 2010-11-01 00:00:00' P12 12 TIMESTAMP' 2010-12-01 00:00:00' P13 13 TIMESTAMP' 2011-01-01 00:00:00' 58
  57. 57. range partition boundaries 59
  58. 58. split by upper bound 60
  59. 59. P02 >= 2010-01-01 P02 < 2010-02-01 PARTITION p01 VALUES LESS THAN (TIMESTAMP' 2010-01-01 00:00:00'), PARTITION p02 VALUES LESS THAN (TIMESTAMP' 2010-02-01 00:00:00'), January not February 61
  60. 60. possible benefits 62
  61. 61. performance 63
  62. 62. partition pruning 64
  63. 63. SQL> set autotrace traceonly explain SQL> select * from DEMO 2 where TSTAMP = to_date('11-JUN-2010'); --------------------------------------------------------------- | Id | Operation | Name | Rows | Pstart| Pstop | --------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | | 1 | PARTITION RANGE SINGLE| | 1 | 7 | 7 | |* 2 | TABLE ACCESS FULL | DEMO | 1 | 7 | 7 | --------------------------------------------------------------- 65
  64. 64. SQL> select partition_name pname, 2 partition_position pos, 3 high_value 4 from user_tab_partitions 5 where table_name = 'DEMO'; PNAME POS HIGH_VALUE ----- ---------- ------------------------------- P01 1 TIMESTAMP' 2010-01-01 00:00:00' P02 2 TIMESTAMP' 2010-02-01 00:00:00' P03 3 TIMESTAMP' 2010-03-01 00:00:00' P04 4 TIMESTAMP' 2010-04-01 00:00:00' P05 5 TIMESTAMP' 2010-05-01 00:00:00' P06 6 TIMESTAMP' 2010-06-01 00:00:00' P07 7 TIMESTAMP' 2010-07-01 00:00:00' P08 8 TIMESTAMP' 2010-08-01 00:00:00' P09 9 TIMESTAMP' 2010-09-01 00:00:00' P10 10 TIMESTAMP' 2010-10-01 00:00:00' P11 11 TIMESTAMP' 2010-11-01 00:00:00' P12 12 TIMESTAMP' 2010-12-01 00:00:00' P13 13 TIMESTAMP' 2011-01-01 00:00:00' 66
  65. 65. more later... 67
  66. 66. dbms_xplan 68
  67. 67. SQL> explain plan for select .... SQL> select * 2 from table(dbms_xplan.display) 69
  68. 68. SQL> select * 2 from table( 3 dbms_xplan.display( 4 format=>'PARTITION -COST -BYTES')); 70
  69. 69. SQL> select * 2 from table(dbms_xplan.display_awr(...)) 71
  70. 70. SQL> select ... SQL> select * 2 from table(dbms_xplan.display_cursor) 72
  71. 71. SQL> select * 2 from table(dbms_xplan.display_plan_baseline) 73
  72. 72. back to range partitioning 74
  73. 73. add / drop move cache control maintenance rebuild backup / read-only compress 75
  74. 74. partition loss availability recovery a little dubious.... 76
  75. 75. multi-column range 77
  76. 76. SQL> create table SALES_DATA 2 ( yyyy number(4) not null, 3 mm number(2) not null, 4 sales_id varchar2(10) not null, 5 amount number(10) 6 ) 7 PARTITION BY RANGE (yyyy, mm) 8 ( 9 PARTITION p01 VALUES LESS THAN (2010,02), 10 PARTITION p02 VALUES LESS THAN (2010,03), 11 PARTITION p03 VALUES LESS THAN (2010,04) ... ... 22 ) 23 / Table created. 78
  77. 77. tiebreaker 79
  78. 78. not multi dimension 80
  79. 79. SQL> create table MOBILE_PHONE 2 ( start_day date not null, 3 end_day date not null, 4 account_id varchar2(10) not null, 5 calls number(10) 6 ) 7 PARTITION BY RANGE (start_day, end_day) 8 ( 9 PARTITION p01 VALUES LESS THAN 10 ('01-FEB-2010','01-FEB-2010'), 11 PARTITION p02 VALUES LESS THAN 12 ('01-MAR-2010','01-MAR-2010'), 13 PARTITION p03 VALUES LESS THAN 14 ('01-APR-2010','01-APR-2010') 15 ) 16 / Table created. 81
  80. 80. SQL> select sum(calls) 2 from MOBILE_PHONE 3 where START_DAY= '12-FEB-2010'; ---------------------------------------------------------------- | Id | Operation | Name | Pstart| Pstop | ---------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | 1 | SORT AGGREGATE | | | | | 2 | PARTITION RANGE SINGLE| | 3 | 3 | |* 3 | TABLE ACCESS FULL | MOBILE_PHONE | 3 | 3 | ---------------------------------------------------------------- 82
  81. 81. SQL> select sum(calls) 2 from MOBILE_PHONE 3 where END_DAY= '12-FEB-2010'; ---------------------------------------------------------------------- | Id | Operation | Name | Pstart| Pstop | ---------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | 1 | SORT AGGREGATE | | | | | 2 | PARTITION RANGE ALL | | 1 | 3 | |* 3 | TABLE ACCESS FULL | MOBILE_PHONE | 1 | 3 | ---------------------------------------------------------------------- 83
  82. 82. 9 PARTITION p01 VALUES LESS THAN 10 ('01-FEB-2010','01-FEB-2010'), 11 PARTITION p02 VALUES LESS THAN 12 ('01-MAR-2010','01-MAR-2010'), 13 PARTITION p03 VALUES LESS THAN 14 ('01-APR-2010','01-APR-2010') SQL> insert into MOBILE_PHONE 2 values ('07-FEB-2010','12-FEB-2010'); SQL> insert into MOBILE_PHONE 2 values ('23-JAN-2010','12-FEB-2010'); SQL> insert into MOBILE_PHONE 2 values ('17-MAR-2010','12-FEB-2010'); 84
  83. 83. better in 11g 85
  84. 84. SQL> select sum(calls) 2 from MOBILE_PHONE 3 where END_DAY= '12-FEB-2010'; ---------------------------------------------------------------------- | Id | Operation | Name | Pstart| Pstop | ---------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | 1 | SORT AGGREGATE | | | | | 2 | PARTITION RANGE MULTI-COLUMN| |KEY(MC)|KEY(MC)| |* 3 | TABLE ACCESS FULL | MOBILE_PHONE |KEY(MC)|KEY(MC)| ---------------------------------------------------------------------- 86
  85. 85. hash partitioning since 8.1 87
  86. 86. big stuff is a pain 88
  87. 87. "metapoor" 89
  88. 88. possible benefits 92
  89. 89. manageability 93
  90. 90. 94
  91. 91. move backup etc 95
  92. 92. insertion performance 96
  93. 93. "buffer busy waits" 97
  94. 94. "enq: HW - contention" 98
  95. 95. "read by other session" 99
  96. 96. 100
  97. 97. less relevant nowadays for tables 101
  98. 98. ASSM 102
  99. 99. automatic segment space management 103
  100. 100. SQL> CREATE TABLESPACE DEMO 2 DATAFILE '...' SIZE 20G 3 EXTENT MANAGEMENT LOCAL 4 SEGMENT SPACE MANAGEMENT AUTO; 104
  101. 101. 105
  102. 102. ...but still very important see later 106
  103. 103. SQL> create table T 2 ( x number(10) ) 3 partition by hash ( x ) 4 partitions 8 5 / Table created. 107
  104. 104. even spread of values 108
  105. 105. SQL> create table T 2 ( x number(10) ) 3 partition by hash ( x ) 4 partitions 8 5 / Table created. 1,2,3,4 .... 100000 SQL> insert into T 2 select level 3 from dual connect by level <= 100000 4 / 100000 rows created. 109
  106. 106. SQL> select DBMS_ROWID.ROWID_OBJECT(rowid) ptn, 2 count(*) 3 from T 4 group by DBMS_ROWID.ROWID_OBJECT(rowid); PTN COUNT(*) ---------- ---------- 72166 12381 72167 12628 72161 12603 72162 12574 72163 12581 72168 12382 72164 12508 72165 12342 110
  107. 107. predicting hash target 111
  108. 108. SQL> select dbms_rowid.ROWID_OBJECT(rowid) ptn, 2 count(*) 3 from T SQL> select ora_hash(x,7), count(*) 4 2 from t dbms_rowid.ROWID_OBJECT(rowid) group by 5 3 group by ora_hash(x,7) order by 2; 4 order by 2; PTN COUNT(*) ---------- ---------- ORA_HASH(X,7) COUNT(*) ------------- 12342 73535 ---------- 73536 4 12381 12342 73538 5 12382 12381 remember these 73534 7 12508 12382 73532 3 12574 12508 73533 1 12581 12574 73531 2 12603 12581 73537 0 12628 12603 6 12628 112
  109. 109. the power of 2 rule 113
  110. 110. SQL> create table T 2 ( x number(10) ) 3 partition by hash ( x ) 4 partitions 4 | 8 | 16 | 32 ... 5 / Table created. 114
  111. 111. SQL> select DBMS_ROWID.ROWID_OBJECT(rowid) ptn, 2 count(*) 3 from T 4 group by DBMS_ROWID.ROWID_OBJECT(rowid); PTN COUNT(*) ---------- ---------- 72166 12381 72167 12628 72161 12603 72162 12574 72163 12581 72168 12382 72164 12508 72165 12342 115
  112. 112. SQL> create table T 2 ( x number(10) ) 3 partition by hash ( x ) 4 partitions 5 5 / Table created. SQL> insert into T 2 select level 3 from dual connect by level <= 100000 4 / 100000 rows created. 116
  113. 113. SQL> select DBMS_ROWID.ROWID_OBJECT(rowid) ptn, 2 count(*) 3 from T 4 group by DBMS_ROWID.ROWID_OBJECT(rowid); PTN COUNT(*) ---------- ---------- 72174 12342 72172 25209 72171 24955 72173 24890 72170 12603 117
  114. 114. why ? 118
  115. 115. deliberately for maintenance... 119
  116. 116. Task: from 5 to 8 partitions 120
  117. 117. "classical" redistribution 121
  118. 118. "every" row moves 122
  119. 119. SQL> select count(*) 2 from T 3 where ora_hash(x,4) != ora_hash(x,7); COUNT(*) ---------- 87564 123
  120. 120. "smart" redistribution 124
  121. 121. SQL> select DBMS_ROWID.ROWID_OBJECT(rowid) ptn, 2 count(*) 3 from T 4 group by DBMS_ROWID.ROWID_OBJECT(rowid); PTN COUNT(*) ---------- ---------- 72174 12342 72172 25209 72171 24955 72173 24890 pick one 72170 12603 5 rows selected. 125
  122. 122. SQL> alter table T add partition; Table altered. SQL> select dbms_rowid.ROWID_OBJECT(rowid) ptn, 2 count(*) 3 from T 4 group by dbms_rowid.ROWID_OBJECT(rowid); PTN COUNT(*) ---------- ---------- 73515 25209 73516 24890 73517 12342 73519 12381 73518 12574 73513 12603 126
  123. 123. SQL> alter table T add partition; Table altered. SQL> select dbms_rowid.ROWID_OBJECT(rowid) ptn, 2 count(*) 3 from T 4 group by dbms_rowid.ROWID_OBJECT(rowid); PTN COUNT(*) ---------- ---------- 73516 24890 73517 12342 73519 12381 73518 12574 73521 12628 73520 12581 73513 12603 127
  124. 124. SQL> alter table T add partition; Table altered. SQL> select dbms_rowid.ROWID_OBJECT(rowid) ptn, 2 count(*) 3 from T 4 group by dbms_rowid.ROWID_OBJECT(rowid); PTN COUNT(*) ---------- ---------- 73517 12342 73523 12382 73522 12508 73519 12381 73518 12574 73521 12628 73520 12581 73513 12603 128
  125. 125. only 1 partition "effort" 129
  126. 126. same for coalesce partition 130
  127. 127. handling a small number of values 131
  128. 128. SQL> create table ... ... 20 values less than ('WB'), 21 values less than ('QLE'), 22 values less than ('SB'), 23 values less than ('VID'), range fiddly.... 132
  129. 129. SQL> select state, ora_hash(state,7) hash 2 from AUST; STATE HASH ----- ---- WA 2 SA 5 NSW 3 VIC 5 hash ... poor distribution 133
  130. 130. list version 9 134
  131. 131. SQL> create table SALES_DATA 2 ( sales_id varchar2(10) not null, 3 location varchar2(3) not null, 4 amount number(10) 5 ) 6 PARTITION BY LIST (location) 7 ( 8 PARTITION NSW VALUES ('NSW'), 9 PARTITION WA VALUES ('WA'), 10 PARTITION QLD VALUES ('QLD'), 11 PARTITION SA VALUES ('SA'), 12 PARTITION VIC VALUES ('VIC'), 13 PARTITION TERR VALUES ('ACT','NT'), 14 PARTITION DREGS VALUES (DEFAULT) 15 ) 18 / Table created. 135
  132. 132. think carefully on DEFAULT add versus split 136
  133. 133. sometimes one level is not enough 137
  134. 134. 138
  135. 135. 139
  136. 136. ranges unevenly distributed 140
  137. 137. deletion of older data 2009 2010 2011 2012 141
  138. 138. composite partitions 142
  139. 139. composite (range + hash) since 8.1 143
  140. 140. SQL> create table COMP 2 ( tstamp timestamp(6) not null, 3 empno number(10) not null, 4 ename varchar2(10) not null, 5 deptno varchar2(10) not null 6 ) 7 PARTITION BY RANGE (TSTAMP) 8 SUBPARTITION BY LIST (deptno) 9 ( 10 PARTITION p01 VALUES LESS THAN 11 (TIMESTAMP' 2010-01-01 00:00:00') 12 (SUBPARTITION p01_d1 VALUES (1), 13 SUBPARTITION p01_d2 VALUES (2), 14 SUBPARTITION p01_d3 VALUES (3), 15 SUBPARTITION p01_d4 VALUES (4)), 16 PARTITION p02 VALUES LESS THAN 17 (TIMESTAMP' 2010-02-01 00:00:00') 18 (SUBPARTITION p02_d1 VALUES (1), 19 SUBPARTITION p02_d2 VALUES (2), 20 SUBPARTITION p02_d3 VALUES (3), 21 SUBPARTITION p02_d4 VALUES (4)), ..... 144
  141. 141. 30 PARTITION p11 VALUES LESS THAN 31 (TIMESTAMP' 2010-11-01 00:00:00') 32 (SUBPARTITION p01_d1 VALUES (1,2), 33 SUBPARTITION p01_d2 VALUES (3,4), 34 PARTITION p12 VALUES LESS THAN 35 (TIMESTAMP' 2010-12-01 00:00:00') 36 PARTITION p13 VALUES LESS THAN 37 (TIMESTAMP' 2011-01-01 00:00:00') ..... recall: coalesce partition 145
  142. 142. long DDL ..... 146
  143. 143. subpartition templates 147
  144. 144. SQL> create table COMP 2 ( tstamp timestamp(6) not null, 3 empno number(10) not null, 4 ename varchar2(10) not null, 5 deptno varchar2(10) not null 6 ) 7 PARTITION BY RANGE (TSTAMP) 8 SUBPARTITION BY LIST (deptno) 9 SUBPARTITION TEMPLATE 10 (SUBPARTITION d1 VALUES (1), 11 SUBPARTITION d2 VALUES (2), 12 SUBPARTITION d3 VALUES (3), implicit 13 SUBPARTITION d4 VALUES (4)) subpar's 14 ( 15 PARTITION p01 VALUES LESS THAN 16 (TIMESTAMP' 2010-01-01 00:00:00'), 17 PARTITION p02 VALUES LESS THAN 18 (TIMESTAMP' 2010-02-01 00:00:00'), 19 .... 148
  145. 145. SQL> select partition_name pname, 2 partition_position pos, 3 high_value 4 from USER_TAB_PARTITIONS 5 where table_name = 'COMP'; PNAME POS HIGH_VALUE ---------- ---------- -------------------------------- P01 1 TIMESTAMP' 2010-01-01 00:00:00' P02 2 TIMESTAMP' 2010-02-01 00:00:00' P03 3 TIMESTAMP' 2010-03-01 00:00:00' P04 4 TIMESTAMP' 2010-04-01 00:00:00' P05 5 TIMESTAMP' 2010-05-01 00:00:00' P06 6 TIMESTAMP' 2010-06-01 00:00:00' P07 7 TIMESTAMP' 2010-07-01 00:00:00' P08 8 TIMESTAMP' 2010-08-01 00:00:00' ... 149
  146. 146. SQL> select subpartition_name pname, 2 subpartition_position pos, 3 high_value 4 from USER_TAB_SUBPARTITIONS 5 where table_name = 'COMP' 6 order by 1,2; PNAME POS HIGH_VALUE ---------- ---------- ---------------------- P01_D1 1 '1' P01_D2 2 '2' P01_D3 3 '3' P01_D4 4 '4' P02_D1 1 '1' P02_D2 2 '2' P02_D3 3 '3' P02_D4 4 '4' P03_D1 1 '1' auto named for ... subpar templates ... 150
  147. 147. partitions logical or physical 151
  148. 148. composite (range + list) since 9 152
  149. 149. composite (anything + anything) since 11 153
  150. 150. interval partitioning 11g 154
  151. 151. the problem with ranges.... 155
  152. 152. ... they are a range 156
  153. 153. require maintenance 157
  154. 154. 25 PARTITION p13 VALUES LESS THAN 26 (TIMESTAMP' 2011-01-01 00:00:00') 27 ); SQL> insert into DEMO 2 values ( to_date('01-JAN-2014'), .... ); insert into DEMO * ERROR at line 1: ORA-14400: inserted partition key does not map to any partition 158
  155. 155. insurance policy 159
  156. 156. 25 PARTITION p13 VALUES LESS THAN 26 (TIMESTAMP' 2011-01-01 00:00:00') 26 PARTITION pmax VALUES LESS THAN 27 (MAXVALUE) 28 ); magic value SQL> insert into DEMO 2 values ( to_date('01-JAN-2014'), .... ); 1 row created. 160
  157. 157. why MAXVALUE might hurt (part 1) 161
  158. 158. split not add 162
  159. 159. SQL> alter table DEMO split partition PMAX 2 at ( TIMESTAMP' 2012-02-01 00:00:00') 3 into ( partition p14, partition pmax ) 4 / Table altered. 163
  160. 160. hoping for empty partition 164
  161. 161. "fast split" partition 165
  162. 162. index hassles see later... 166
  163. 163. "solved" in 11g 167
  164. 164. 168
  165. 165. interval partitioning 169
  166. 166. SQL> create table DEMO 2 ( tstamp timestamp(6) not null, 3 empno number(10) not null, 4 ename varchar2(10) not null, 5 deptno varchar2(10) not null 6 ) 7 PARTITION BY RANGE (TSTAMP) 8 INTERVAL( NUMTOYMINTERVAL(1,'MONTH')) 9 ( 10 PARTITION P00 VALUES LESS THAN 11 (TIMESTAMP' 2010-01-01 00:00:00') 11 ); Table created. 170
  167. 167. partitions created as required 171
  168. 168. SQL> select PARTITION_NAME, HIGH_VALUE 2 from user_tab_partitions 3 where table_name = 'DEMO'; PARTITION_NAME HIGH_VALUE ------------------------- -------------------------------- P00 TIMESTAMP' 2010-01-01 00:00:00' SQL> insert into DEMO 2 values ( to_date('12-DEC-2011'),....); 1 row created. SQL> select PARTITION_NAME, HIGH_VALUE 2 from user_tab_partitions 3 where table_name = 'DEMO'; PARTITION_NAME HIGH_VALUE ------------------------- -------------------------------- P00 TIMESTAMP' 2010-01-01 00:00:00' SYS_P362 TIMESTAMP' 2012-01-01 00:00:00' 172
  169. 169. gaps allowed 173
  170. 170. range partition boundaries Length Length Length 174
  171. 171. partition name control lost can rename.... 175
  172. 172. convert range to interval 176
  173. 173. original range version SQL> alter table DEMO 2 SET INTERVAL ( NUMTOYMINTERVAL(1,'MONTH') ); Table altered. 177
  174. 174. SQL> insert into DEMO 2 values ( to_date('01-JAN-2017'),....); 1 row created. 178
  175. 175. SQL> select partition_name pname, 2 partition_position pos, 3 high_value 4 from user_tab_partitions 5 where table_name = 'DEMO'; PNAME POS HIGH_VALUE ------------ ---------- -------------------------------- P01 1 TIMESTAMP' 2010-01-01 00:00:00' P02 2 TIMESTAMP' 2010-02-01 00:00:00' P03 3 TIMESTAMP' 2010-03-01 00:00:00' P04 4 TIMESTAMP' 2010-04-01 00:00:00' ... P10 10 TIMESTAMP' 2010-10-01 00:00:00' P11 11 TIMESTAMP' 2010-11-01 00:00:00' P12 12 TIMESTAMP' 2010-12-01 00:00:00' P13 13 TIMESTAMP' 2011-01-01 00:00:00' SYS_P1091 14 TIMESTAMP' 2017-02-01 00:00:00' 179
  176. 176. but be careful ... 180
  177. 177. hybrid range range range interval 181
  178. 178. is it range or interval ? 182
  179. 179. SQL> desc DBA_TAB_PARTITIONS Name Null? Type ----------------------- -------- ---------------- TABLE_OWNER VARCHAR2(30) TABLE_NAME VARCHAR2(30) COMPOSITE VARCHAR2(3) PARTITION_NAME VARCHAR2(30) SUBPARTITION_COUNT NUMBER HIGH_VALUE LONG ? HIGH_VALUE_LENGTH PARTITION_POSITION TABLESPACE_NAME NUMBER NUMBER VARCHAR2(30) ... LOGGING VARCHAR2(7) COMPRESSION VARCHAR2(8) COMPRESS_FOR VARCHAR2(18) NUM_ROWS NUMBER BUFFER_POOL VARCHAR2(7) GLOBAL_STATS VARCHAR2(3) USER_STATS VARCHAR2(3) 183
  180. 180. SQL> select o.subname, 2 decode(bitand(tp.flags,32768), 3 32768,'YES','NO') interval 4 from SYS.TABPART$ tp, SYS.OBJ$ o 6 where tp.obj# = o.obj# 6 and o.name = 'DEMO'; SUBNAME INT ------------------------------ --- P01 NO P02 NO P03 NO P04 NO P05 NO ... P11 NO P12 NO P13 NO SYS_P1091 YES 14 rows selected. 184
  181. 181. fixed in 11.2 185
  182. 182. high range value gets "stuck" 186
  183. 183. SQL> insert into DEMO 2 values ( to_date('01-JAN-2017'),...); 1 row created. SQL> insert into DEMO 2 values ( to_date('01-JAN-2016'),...); 1 row created. 187
  184. 184. SQL> select partition_name pname, 2 partition_position pos, 3 high_value 4 from user_tab_partitions 5 where table_name = 'DEMO'; PNAME POS HIGH_VALUE ------------ ---------- ------------------------------- P01 1 TIMESTAMP' 2010-01-01 00:00:00' P02 2 TIMESTAMP' 2010-02-01 00:00:00' P03 3 TIMESTAMP' 2010-03-01 00:00:00' P04 4 TIMESTAMP' 2010-04-01 00:00:00' ... P13 13 TIMESTAMP' 2011-01-01 00:00:00' SYS_P1112 14 TIMESTAMP' 2016-02-01 00:00:00' SYS_P1111 15 TIMESTAMP' 2017-02-01 00:00:00' 188
  185. 185. SQL> alter table DEMO drop partition P01; Table altered. SQL> alter table DEMO drop partition P02; Table altered. SQL> alter table DEMO drop partition P13; alter table DEMO drop partition P13 * ERROR at line 1: ORA-14758: Last partition in the range section cannot be dropped 189
  186. 186. Length Length Length 190
  187. 187. workarounds (maybe) unpleasant.... 191
  188. 188. SQL> alter table DEMO set interval ( ); Table altered. SQL> alter table DEMO 2 set interval (NUMTOYMINTERVAL(1,'MONTH')); Table altered. 192
  189. 189. SQL> alter table DEMO merge partitions 2 for (TIMESTAMP' 2010-12-30 00:00:00'), 3 for (TIMESTAMP' 2016-01-10 00:00:00'); Table altered. 193
  190. 190. 11.2 194
  191. 191. SQL> alter table DEMO 2 set interval (NUMTOYMINTERVAL(1,'MONTH')); Table altered. 195
  192. 192. why MAXVALUE might hurt (part 2) 196
  193. 193. SQL> create table DEMO 2 ( tstamp timestamp(6) not null, 3 empno number(10) not null, 4 ename varchar2(10) not null, 5 deptno varchar2(10) not null 6 ) 7 PARTITION BY RANGE (TSTAMP) 8 ( 9 PARTITION p01 VALUES LESS THAN 10 (TIMESTAMP' 2010-01-01 00:00:00'), ... 25 partition PMAX values less than (MAXVALUE) 26 ) 27 / Table created. 197
  194. 194. SQL> alter table DEMO 2 set interval ( NUMTOYMINTERVAL(1,'MONTH') ); * ERROR at line 1: ORA-14759: SET INTERVAL is not legal on this table. 198
  195. 195. explain plan anomaly 199
  196. 196. INTERVAL = "1 million partitions" 200
  197. 197. SQL> create table DEMO 2 ( tstamp timestamp(6) not null, 3 empno number(10) not null, 4 ename varchar2(10) not null, 5 deptno varchar2(10) not null 6 ) 7 PARTITION BY RANGE (TSTAMP) 8 INTERVAL( NUMTOYMINTERVAL(1,'MONTH')) 9 ( 10 PARTITION P00 VALUES LESS THAN 11 (TIMESTAMP' 2010-01-01 00:00:00') 12 ); Table created. 201
  198. 198. SQL> select * from DEMO; ------------------------------------------------------------ | Id | Operation | Name | Rows | Pstart| Pstop | ------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | | | | 1 | PARTITION RANGE ALL| | 1 | 1 |1048575| | 2 | TABLE ACCESS FULL | DEMO | 1 | 1 |1048575| ------------------------------------------------------------ 202
  199. 199. partitioned tables ... the bigger picture 203
  200. 200. SALES SQL> desc SALES Name Null? Type -------------------- -------- -------------- SALE_DATE NOT NULL DATE ... 2009 2010 2011 2012 SALES_ITEMS SQL> desc SALES_ITEMS Name Null? Type -------------------- -------- ----------- SALE_ID NOT NULL NUMBER(12) ITEM_ID NOT NULL NUMBER(12) ... 204
  201. 201. reference partitions 11g 205
  202. 202. SQL> create table PARENT 2 ( d date not null, 3 p number(10) not null, 4 pad char(10) 5 ) 6 PARTITION BY RANGE (d) 7 ( 8 PARTITION p1 VALUES LESS THAN ( to_date('01-JAN-2010')), 9 PARTITION p2 VALUES LESS THAN ( to_date('01-FEB-2010')), 10 PARTITION p3 VALUES LESS THAN ( to_date('01-MAR-2010')), 11 PARTITION p4 VALUES LESS THAN ( to_date('01-APR-2010')), 12 PARTITION p5 VALUES LESS THAN ( to_date('01-MAY-2010')), 13 PARTITION p6 VALUES LESS THAN ( to_date('01-JUN-2010')), 14 PARTITION p7 VALUES LESS THAN ( to_date('01-JUL-2010')), 15 PARTITION p8 VALUES LESS THAN ( to_date('01-AUG-2010')), 16 PARTITION p9 VALUES LESS THAN ( to_date('01-SEP-2010')) 17 ); Table created. SQL> alter table PARENT add primary key ( p ); Table altered. 206
  203. 203. SQL> create table CHILD 2 ( p number(10) not null, 3 c number(10) not null, 4 constraint CHILD_FK foreign key ( p ) 5 references PARENT (p) 6 on delete cascade 7 ) 8 PARTITION BY REFERENCE (CHILD_FK) 9 / Table created. 207
  204. 204. SQL> insert into PARENT 2 select sysdate+rownum, rownum, rownum 3 from dual connect by level <= 100 4 / 100 rows created. SQL> insert into CHILD 2 select rownum, rownum 3 from dual connect by level <= 100 4 / 100 rows created. 208
  205. 205. SQL> exec dbms_stats.gather_table_stats(user,'CHILD'); PL/SQL procedure successfully completed. SQL> select partition_name, num_rows 2 from USER_TAB_PARTITIONS 3 where table_name = 'CHILD'; PARTITION_NAME NUM_ROWS ------------------------------ ---------- P1 0 P2 0 P3 0 P4 0 P5 9 P6 31 P7 30 P8 30 P9 0 209
  206. 206. seems good .... but 210
  207. 207. null SQL> create table CHILD 2 ( p number(10), 3 c number(10), 4 constraint CHILD_FK foreign key ( p ) 5 references PARENT (p) 6 ) 7 PARTITION BY REFERENCE (CHILD_FK) 8 / PARTITION BY REFERENCE (CHILD_FK) * ERROR at line 7: ORA-14652: reference partitioning foreign key is not supported 211
  208. 208. SQL> create table PARENT 2 ( d date not null, 3 p number(10) not null, 4 pad char(10) 5 ) 6 PARTITION BY RANGE (d) 7 INTERVAL( NUMTOYMINTERVAL(1,'MONTH')) 8 ( PARTITION VALUES LESS THAN ( to_date('01-JAN-2010')) ); Table created. SQL> create table CHILD 2 ( p number(10) not null, 3 c number(10) not null, 4 constraint CHILD_FK foreign key ( p ) 5 references PARENT (p) 6 on delete cascade 7 ) 8 PARTITION BY REFERENCE (CHILD_FK); create table CHILD * ERROR at line 1: ORA-14659: Partitioning method of the parent table is not supported 212
  209. 209. but the following "works".... 213
  210. 210. SQL> alter table PARENT 2 set INTERVAL( NUMTOYMINTERVAL(1,'MONTH')); Table altered. SQL> insert into PARENT values (sysdate+1000,-1,'x'); 1 row created. SQL> select partition_name 2 from user_tab_partitions pk=-1 3 where table_name = 'PARENT'; PARTITION_NAME ------------------------------ SYS_P1196 P1 P2 P3 ... 214
  211. 211. SQL> insert into CHILD values (-1,0); insert into CHILD values (-1,0) * ERROR at line 1: ORA-14401: inserted partition key is outside specified partition 215
  212. 212. dropping requires order 216
  213. 213. SQL> drop table PARENT; drop table PARENT * ERROR at line 1: ORA-02449: unique/primary keys in table referenced by foreign keys SQL> drop table PARENT cascade constraints; drop table PARENT cascade constraints * ERROR at line 1: ORA-14656: cannot drop the parent of a reference- partitioned table 217
  214. 214. Suboptimal Query when Gather Partition Stats on Reference Partitioned Wrong Results In 11g On Reference Partitioned Table ORA-7445[KKPAMDINFO] ON SELECT AGAINST A REFERENCE PARTITIONED TABLE its a very new feature Drop of reference partition not allowed (ORA-2266) with FK between siblings UNIQUE INDEX NOT WORKING PROPERLY ON PARTITIONED BY REFERENCE TABLE ALLOW DROP PARTITION TO SUCCEED ON REFERENCED PARTITION WITHOUT CORRUPTING DATA. 218
  215. 215. Part 2 indexes on partitioned tables 219
  216. 216. 220
  217. 217. SALES 2009 2010 2011 2012 SQL> create index SALES_IX on SALES ( CUSTOMER ); 221
  218. 218. 2009 2010 2011 2012 222
  219. 219. "global" index 223
  220. 220. big....really big extended rowid 224
  221. 221. ILM issues 225
  222. 222. 2009 2010 2011 2012 SQL> alter table SALES drop partition SALES_2009 226
  223. 223. SQL> create index DEMO_IX on DEMO ( empno ); Index created. SQL> select status 2 from user_indexes 3 where index_name = 'DEMO_IX'; STATUS -------- VALID SQL> select * from DEMO where empno = 123; --------------------------------------------------------------------- | Id | Operation | Name |Pstart| Pstop | -------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | 1 | TABLE ACCESS BY GLOBAL INDEX ROWID| DEMO |ROWID | ROWID | |* 2 | INDEX RANGE SCAN | DEMO_IX | | | --------------------------------------------------------------------- 227
  224. 224. SQL> alter table DEMO drop partition P06; Table altered. SQL> select status 2 from user_indexes 3 where index_name = 'DEMO_IX'; STATUS -------- UNUSABLE SQL> select * from DEMO where empno = 123; ------------------------------------------------------------ | Id | Operation | Name | Rows | Pstart| Pstop | ------------------------------------------------------------ | 0 | SELECT STATEMENT | | 50 | | | | 1 | PARTITION RANGE ALL| | 50 | 1 | 13 | |* 2 | TABLE ACCESS FULL | DEMO | 50 | 1 | 13 | ------------------------------------------------------------ 228
  225. 225. SQL> select value 2 from v$parameter 3 where name = 'skip_unusable_indexes'; VALUE ------------------------------ TRUE 229
  226. 226. keep the index valid 230
  227. 227. 2009 2010 2011 2012 SQL> alter table SALES drop partition SALES_2009 2 update indexes; 231
  228. 228. undo large delete redo 232
  229. 229. merge split similar issues exchange 233
  230. 230. an alternative 234
  231. 231. "local" index 235
  232. 232. 2009 2010 2011 2012 SQL> create index SALES_IX ON SALES ( CUSTOMER ) 2 LOCAL; 236
  233. 233. smaller chunks 237
  234. 234. smaller rowid's 238
  235. 235. 2009 2010 2011 2012 SQL> alter table SALES drop partition SALES_2009; 239
  236. 236. SQL> create index DEMO_IX on DEMO ( empno ) LOCAL; Index created. SQL> select partition_name, status 2 from user_ind_partitions 3 where index_name = 'DEMO_IX'; PARTITION_NAME STATUS ------------------------------ ------- P01 USABLE P02 USABLE P03 USABLE P04 USABLE P05 USABLE P06 USABLE P07 USABLE ... 240
  237. 237. SQL> alter table DEMO drop partition P06; Table altered. SQL> select partition_name, status 2 from user_ind_partitions 3 where index_name = 'DEMO_IX'; PARTITION_NAME STATUS ------------------------------ ------- P01 USABLE P02 USABLE P03 USABLE P04 USABLE P05 USABLE P06 USABLE P07 USABLE ... 241
  238. 238. awesome for ILM 242
  239. 239. handlng old data 243
  240. 240. 2009 2010 2011 2012 SQL> alter table SALES move partition SALES_2009 2 COMPRESS; 244
  241. 241. RMAN 2009 2010 2011 2012 SQL> alter table SALES move partition SALES_2009 2 TABLESPACE CRAPPY_OLD_DISK; SQL> alter tablespace CRAPPY_OLD_DISK READ ONLY; 245
  242. 242. 11.2 very cool 246
  243. 243. "segment-less" segments 247
  244. 244. 2009 2010 2011 2012 SQL> alter index SALES_IX partition SALES_IX_2009 2 UNUSABLE; 248
  245. 245. handlng new data 249
  246. 246. 2010 2011 2013 2012 2013 SQL> alter table SALES exchange 2 partition SALES_2013 with 3 table NEW_SALES; 250
  247. 247. local = good
  248. 248. global = bad 252
  249. 249. NO ! 253
  250. 250. different "target audience" 254
  251. 251. SQL> create index SALES_IX on SALES ( CUSTOMER ) LOCAL; 123 123 123 123 2009 2010 2011 2012 SQL> select * 2 from SALES 3 where CUSTOMER = 123; 255
  252. 252. can be much much worse... 256
  253. 253. WA VIC WA VIC WA VIC WA VIC 2009 2010 2011 2012 NSW QLD NSW QLD NSW QLD NSW QLD SQL> select * 2 from SALES 3 where CUSTOMER = 123; 257
  254. 254. explain plan 258
  255. 255. SQL> select * from SALES 2 where CUSTOMER= 123; ---------------------------------------------------------------------- | Id | Operation | Name |Pstart | Pstop | ---------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | 1 | PARTITION RANGE ALL | | 1 | 13 | | 2 | TABLE ACCESS BY LOCAL INDEX ROWID| SALES | 1 | 13 | |* 3 | INDEX RANGE SCAN | SALES_IX| 1 | 13 | ---------------------------------------------------------------------- 259
  256. 256. SQL> create index SALES_IX on SALES ( CUSTOMER ) LOCAL; 123 123 123 123 2009 2010 2011 2012 SQL> select * 2 from SALES 3 where CUSTOMER = 123; 260
  257. 257. "so global for index lookups then".... 261
  258. 258. NO ! 262
  259. 259. 123 2009 2010 2011 2012 SQL> select * 2 from SALES 3 where CUSTOMER = 123 4 and YEAR = 2010; 263
  260. 260. careful design 264
  261. 261. application compromises eg unique keys 265
  262. 262. so far ... "equipartition" 266
  263. 263. SALES SQL> create index SALES_IX ON SALES ( CUSTOMER ) 2 global 3 partition by .... 267
  264. 264. 2009 2010 2011 2012 SQL> create index SALES_IX 2 on SALES ( location, empno ) 3 global partition by range ( location ) 4 ( partition p0 values less than (1), 6 partition p1 values less than (2), ... 12 partition pmax values less than (maxvalue) 13 ); Index created. 268
  265. 265. rare .... 269
  266. 266. ...one special case 10g+ 270
  267. 267. hash partitioned index 271
  268. 268. recall: hash partitioned tables 272
  269. 269. ASSM concurrency 273
  270. 270. indexes a problem 274
  271. 271. 275
  272. 272. hash partitioned indexes 276
  273. 273. SQL> create index SALES_PK on SALES( TXN_ID ) 2 global partition by hash ( TXN_ID ) 3 partitions 8 4 / Index created. 277
  274. 274. 278
  275. 275. only for equality primary keys 279
  276. 276. beware the NOSORT 280
  277. 277. reference partitions and indexes 281
  278. 278. SALES 2009 2010 2011 2012 SALES_ITEMS 2009 2010 2011 2012 282
  279. 279. take care with ILM 283
  280. 280. SQL> alter table PARENT drop partition P6; Table altered. SQL> select partition_name 2 from user_tab_partitions 3 where table_name = 'CHILD'; PARTITION_NAME ------------------------------ P1 P2 P3 P4 P5 P7 P8 P9 284
  281. 281. SQL> alter table PARENT truncate partition P7; alter table PARENT truncate partition P7 * ERROR at line 1: ORA-02266: unique/primary keys in table referenced by enabled foreign keys SQL> alter table CHILD truncate partition P7; Table truncated. SQL> alter table PARENT truncate partition P7; Table truncated. gap 285
  282. 282. SQL> select index_name, status from user_indexes; INDEX_NAME STATUS ------------------------------ -------- PARENT_PK UNUSABLE CHILD_PK UNUSABLE 286
  283. 283. exchange is difficult... 287
  284. 284. plus more restrictions..... 288
  285. 285. Part 3 partition queries 289
  286. 286. partition pruning 290
  287. 287. efficiency = data required / data scanned 291
  288. 288. SQL> create table DEMO 2 ( tstamp timestamp(6) not null, 3 empno number(10) not null, 4 ename varchar2(10) not null, 5 deptno varchar2(10) not null 6 ) 7 PARTITION BY RANGE (TSTAMP) 8 ( 9 PARTITION p01 VALUES LESS THAN 10 (TIMESTAMP' 2010-01-01 00:00:00'), 11 PARTITION p02 VALUES LESS THAN 12 (TIMESTAMP' 2010-02-01 00:00:00'), 13 PARTITION p03 VALUES LESS THAN 14 (TIMESTAMP' 2010-03-01 00:00:00'), ... ... 25 PARTITION p13 VALUES LESS THAN 26 (TIMESTAMP' 2011-01-01 00:00:00') 27 ); Table created. 292
  289. 289. 360 days SQL> insert /*+ APPEND */ into DEMO 2 select trunc(sysdate,'YYYY')+rownum/( 1000000 / 360 ), 3 rownum, 4 rownum, 5 mod(rownum,1000) 6 from dual 7 connect by level <= 1000000 8 / 1000000 rows created. 293
  290. 290. SQL> select * from DEMO 2 where TSTAMP = to_date('01-JUN-2010'); --------------------------------------------------------------- | Id | Operation | Name | Rows | Pstart| Pstop | --------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | | 1 | PARTITION RANGE SINGLE| | 1 | 7 | 7 | |* 2 | TABLE ACCESS FULL | DEMO | 1 | 7 | 7 | --------------------------------------------------------------- 294
  291. 291. SQL> select * from DEMO 2 where TRUNC(TSTAMP) = to_date('01-JUN-2010'); ------------------------------------------------------------ | Id | Operation | Name | Rows | Pstart| Pstop | ------------------------------------------------------------ | 0 | SELECT STATEMENT | | 10000 | | | | 1 | PARTITION RANGE ALL| | 10000 | 1 | 13 | |* 2 | TABLE ACCESS FULL | DEMO | 10000 | 1 | 13 | ------------------------------------------------------------ 295
  292. 292. static versus dynamic 296
  293. 293. SQL> select * from DEMO 2 where TSTAMP = :b1; --------------------------------------------------------------- | Id | Operation | Name | Rows | Pstart| Pstop | --------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | | 1 | PARTITION RANGE SINGLE| | 1 | KEY | KEY | |* 2 | TABLE ACCESS FULL | DEMO | 1 | KEY | KEY | --------------------------------------------------------------- 297
  294. 294. lots of power varies by version 298
  295. 295. SQL> select * from DEMO 2 where TSTAMP between to_date('12-JAN-2010') 3 and to_date('07-FEB-2010') 4 or TSTAMP between to_date('03-JUN-2010') 5 and to_date('06-AUG-2010'); ----------------------------------------------------------- | Id | Operation | Name | Rows | Pstart| Pstop | ----------------------------------------------------------- | 0 | SELECT STATEMENT | | 240K| | | | 1 | PARTITION RANGE OR| | 240K|KEY(OR)|KEY(OR)| |* 2 | TABLE ACCESS FULL| DEMO | 240K|KEY(OR)|KEY(OR)| ----------------------------------------------------------- 299
  296. 296. SQL> select * from DEMO 2 where TSTAMP in (to_date('01-JUN-2010'), 3 to_date('01-DEC-2010')); --------------------------------------------------------------- | Id | Operation | Name | Rows | Pstart| Pstop | --------------------------------------------------------------- | 0 | SELECT STATEMENT | | 2 | | | | 1 | PARTITION RANGE INLIST| | 2 |KEY(I) |KEY(I) | |* 2 | TABLE ACCESS FULL | DEMO | 2 |KEY(I) |KEY(I) | --------------------------------------------------------------- 300
  297. 297. limitations of explain plan 301
  298. 298. SQL> select * from DEMO 2 where TSTAMP in (to_date('01-JUN-2010'), 3 to_date('01-DEC-2010')); --------------------------------------------------------------- | Id | Operation | Name | Rows | Pstart| Pstop | --------------------------------------------------------------- | 0 | SELECT STATEMENT | | 2 | | | | 1 | PARTITION RANGE INLIST| | 2 |KEY(I) |KEY(I) | |* 2 | TABLE ACCESS FULL | DEMO | 2 |KEY(I) |KEY(I) | --------------------------------------------------------------- JUN JUL AUG SEP OCT NOV DEC 302
  299. 299. July SQL> alter table DEMO move partition P08 tablespace USERS; Table altered. SQL> alter tablespace USERS offline; Tablespace altered. SQL> select count(*) from DEMO 2 where TSTAMP in (to_date('01-JUN-2010'), 3 to_date('01-DEC-2010')); COUNT(*) ---------- 1234 303
  300. 300. SQL> select count(*) from DEMO 2 where TSTAMP in (to_date('01-JUN-2010'), 3 to_date('01-JUL-2010')); select count(*) from DEMO * ERROR at line 1: ORA-00376: file 4 cannot be read at this time ORA-01110: data file 4: 'C:ORACLEDB11USERS01.DBF' 304
  301. 301. "NO OP" pruning 305
  302. 302. SQL> select * from DEMO 2 where TSTAMP = to_date('01-JUN-2020'); -------------------------------------------------------------- | Id | Operation | Name | Rows | Pstart| Pstop | -------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | | 1 | PARTITION RANGE EMPTY| | 1 |INVALID|INVALID| |* 2 | TABLE ACCESS FULL | DEMO | 1 |INVALID|INVALID| -------------------------------------------------------------- 306
  303. 303. pruning lists 307
  304. 304. SQL> create table SALES 2 ( sales_id varchar2(10) not null, 3 location varchar2(3) not null, 4 amount number(10) 5 ) 6 PARTITION BY LIST (location) 7 ( 8 PARTITION NSW VALUES ('NSW'), 9 PARTITION WA VALUES ('WA'), 10 PARTITION QLD VALUES ('QLD'), 11 PARTITION SA VALUES ('SA'), 12 PARTITION VIC VALUES ('VIC'), 13 PARTITION TERR VALUES ('ACT','NT') 14 ) 15 / Table created. 308
  305. 305. SQL> select * from sales 2 where location = 'WA'; --------------------------------------------------------------- | Id | Operation | Name | Rows | Pstart| Pstop | --------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | | 1 | PARTITION LIST SINGLE| | 1 | KEY | KEY | | 2 | TABLE ACCESS FULL | SALES | 1 | 2 | 2 | --------------------------------------------------------------- 309
  306. 306. SQL> select * from sales 2 where location like 'S%'; --------------------------------------------------------------- | Id | Operation | Name | Rows | Pstart| Pstop | --------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | | 1 | PARTITION LIST SINGLE| | 1 | KEY | KEY | | 2 | TABLE ACCESS FULL | SALES | 1 | 4 | 4 | --------------------------------------------------------------- 310
  307. 307. SQL> select * from sales 2 where location NOT in ('WA','NSW'); ------------------------------------------------------------ | Id | Operation | Name | Rows | Pstart| Pstop | ------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | | | | 1 | PARTITION LIST ALL| | 1 | 1 | 6 | |* 2 | TABLE ACCESS FULL| SALES | 1 | 1 | 6 | ------------------------------------------------------------ 311
  308. 308. pruning composites 312
  309. 309. SQL> create table COMP 2 ( tstamp timestamp(6) not null, 3 empno number(10) not null, 4 ename varchar2(10) not null, 5 deptno varchar2(10) not null 6 ) 7 PARTITION BY RANGE (TSTAMP) 8 SUBPARTITION BY LIST (deptno) 9 SUBPARTITION TEMPLATE 10 (SUBPARTITION d1 VALUES (1), 11 SUBPARTITION d2 VALUES (2), 12 SUBPARTITION d3 VALUES (3), 13 SUBPARTITION d4 VALUES (4)) 14 ( 15 PARTITION p01 VALUES LESS THAN 16 (TIMESTAMP' 2010-01-01 00:00:00'), 17 PARTITION p02 VALUES LESS THAN 18 (TIMESTAMP' 2010-02-01 00:00:00'), 19 .... 313
  310. 310. SQL> select * from COMP 2 where TSTAMP = to_date('01-JUN-2010') 3 and DEPTNO = 2; --------------------------------------------------------------- | Id | Operation | Name | Rows | Pstart| Pstop | --------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | | 1 | PARTITION RANGE SINGLE| | 1 | 7 | 7 | | 2 | PARTITION LIST SINGLE| | 1 | 2 | 2 | |* 3 | TABLE ACCESS FULL | COMP | 1 | 26 | 26 | --------------------------------------------------------------- 314
  311. 311. SQL> select * from COMP 2 where DEPTNO = 3; --------------------------------------------------------------- | Id | Operation | Name | Rows | Pstart| Pstop | --------------------------------------------------------------- | 0 | SELECT STATEMENT | | 250K| | | | 1 | PARTITION RANGE ALL | | 250K| 1 | 13 | | 2 | PARTITION LIST SINGLE| | 250K| 3 | 3 | | 3 | TABLE ACCESS FULL | COMP | 250K| KEY | KEY | --------------------------------------------------------------- 315
  312. 312. pruning by subquery 316
  313. 313. SQL> select e.deptno, max(d.empno) 2 from DEMO d, scott.emp e 3 where d.tstamp = e.hiredate 4 and e.sal < 10000 5 group by e.deptno; ------------------------------------------------------------------- | Id | Operation | Name | Rows | Pstart| Pstop | ------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 14 | | | | 1 | HASH GROUP BY | | 14 | | | |* 2 | HASH JOIN | | 14 | | | |* 3 | TABLE ACCESS FULL | EMP | 14 | | | | 4 | PARTITION RANGE SUBQUERY| | 1000K|KEY(SQ)|KEY(SQ)| | 5 | TABLE ACCESS FULL | DEMO | 1000K|KEY(SQ)|KEY(SQ)| ------------------------------------------------------------------- 317
  314. 314. 11g maybe 10.2 ? 318
  315. 315. SQL> select e.deptno, max(d.empno) 2 from demo d, scott.emp e 3 where d.tstamp = e.hiredate 4 and e.sal < 10000 5 group by e.deptno; ----------------------------------------------------------------- | Id | Operation | Name | Pstart| Pstop | ----------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | 1 | HASH GROUP BY | | | | |* 2 | HASH JOIN | | | | | 3 | PART JOIN FILTER CREATE | :BF0000 | | | |* 4 | TABLE ACCESS FULL | EMP | | | | 5 | PARTITION RANGE JOIN-FILTER| |:BF0000|:BF0000| | 6 | TABLE ACCESS FULL | DEMO |:BF0000|:BF0000| ----------------------------------------------------------------- 319
  316. 316. | 3 | PART JOIN FILTER CREATE | :BF0000 | | | |* 4 | TABLE ACCESS FULL | EMP | | | | 5 | PARTITION RANGE JOIN-FILTER| |:BF0000|:BF0000| | 6 | TABLE ACCESS FULL | DEMO |:BF0000|:BF0000| ----------------------------------------------------------------- huh ? 320
  317. 317. bloom filters 321
  318. 318. The Bloom filter...is a space-efficient probabilistic data structure that is used to test whether an element is a member of a set. - Wikipedia 322
  319. 319. wtf ? 323
  320. 320. "b" bits "h" hash functions 324
  321. 321. b0 b1 h1 b2 b3 data h2 b4 h3 b5 b6 b7 325
  322. 322. b0 b1 h1 b2 b3 data h2 b4 h3 b5 b6 b7 326
  323. 323. b0 b1 h1 b2 b3 data h2 b4 h3 b5 b6 b7 327
  324. 324. b0 b1 h1 b2 b3 data h2 b4 h3 b5 b6 b7 328
  325. 325. b0 b1 h1 b2 b3 data h2 b4 h3 b5 b6 b7 329
  326. 326. b0 b1 b2 h1 b3 h2 matching b4 data? h3 b5 b6 b7 330
  327. 327. b0 b1 b2 h1 do the b3 "real" h2 matching work b4 data? h3 b5 b6 b7 331
  328. 328. b0 b1 b2 h1 do the b3 "real" h2 matching work b4 data? h3 b5 b6 b7 332
  329. 329. "meta-poor" 333
  330. 330. 334
  331. 331. 335
  332. 332. "are you joking...try in 6 months" 336
  333. 333. "yes, we have some" 337
  334. 334. 338
  335. 335. false positives possible 339
  336. 336. false negatives impossible 340
  337. 337. they are here to stay.... 341
  338. 338. SQL> alter session set "_bloom_filter_enabled" = false; SQL> alter session set "_bloom_pruning_enabled" = false; 342
  339. 339. other partitioning benefits 343
  340. 340. partition wise join 344
  341. 341. SQL> select d.*, d2.* 2 from DEMO d, DEMO2 d2 3 where d.TSTAMP = d2.TSTAMP; ------------------------------------------------------------- | Id | Operation | Name | Rows | Pstart| Pstop | ------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1003K| | | | 1 | PARTITION RANGE ALL| | 1003K| 1 | 13 | |* 2 | HASH JOIN | | 1003K| | | | 3 | TABLE ACCESS FULL| DEMO | 1000K| 1 | 13 | | 4 | TABLE ACCESS FULL| DEMO2 | 1000K| 1 | 13 | ------------------------------------------------------------- 345
  342. 342. "big deal" 346
  343. 343. meta-poor 347
  344. 344. 348
  345. 345. 1000 cars north of Perth 1000 cars south of Perth 349
  346. 346. 350
  347. 347. "replace damaged models at the north yard with matching models from the south yard" 351
  348. 348. 352
  349. 349. SQL> select ... 2 from NORTH n, SOUTH s 3 where n.MODEL = s.MODEL ---------------------------------------------------------------- | Id | Operation | Name | Pstart| Pstop | ---------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | |* 1 | HASH JOIN | | | | | 3 | PARTITION RANGE ALL | | 1 | 2 | | 4 | TABLE ACCESS FULL | NORTH | 1 | 2 | | 5 | PARTITION RANGE ALL | | 1 | 2 | | 6 | TABLE ACCESS FULL | SOUTH | 1 | 2 | ---------------------------------------------------------------- 353
  350. 350. NORTH 4WD SMART CARS SOUTH 4WD SMART CARS 354
  351. 351. partition wise join 355
  352. 352. SQL> select ... 2 from NORTH n, SOUTH s 3 where n.model = s.model ------------------------------------------------------------- | Id | Operation | Name | Rows | Pstart| Pstop | ------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1003K| | | | 1 | PARTITION RANGE ALL| | 1003K| 1 | 2 | |* 2 | HASH JOIN | | 1003K| | | | 3 | TABLE ACCESS FULL| NORTH | 1000K| 1 | 2 | | 4 | TABLE ACCESS FULL| SOUTH | 1000K| 1 | 2 | ------------------------------------------------------------- 356
  353. 353. great parallel benefits 357
  354. 354. SQL> select /*+ PARALLEL(n) PARALLEL(s) */ ... 2 from north n, south s 3 where n.model = s.model ---------------------------------------------------------------------------------------------- | Id | Operation | Name | Pstart| Pstop | TQ |IN-OUT| PQ Distrib | ---------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | | | | 1 | PX COORDINATOR | | | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10001 | | | Q1,01 | P->S | QC (RAND) | |* 3 | HASH JOIN | | | | Q1,01 | PCWP | | | 4 | PX BLOCK ITERATOR | | 1 | 2 | Q1,01 | PCWC | | | 5 | TABLE ACCESS FULL | NORTH | 1 | 2 | Q1,01 | PCWP | | | 6 | BUFFER SORT | | | | Q1,01 | PCWC | | | 7 | PX RECEIVE | | | | Q1,01 | PCWP | | | 8 | PX SEND BROADCAST LOCAL| :TQ10000 | | | Q1,00 | P->P | BCST LOCAL | | 9 | PX BLOCK ITERATOR | | 1 | 2 | Q1,00 | PCWC | | | 10 | TABLE ACCESS FULL | SOUTH | 1 | 2 | Q1,00 | PCWP | | ---------------------------------------------------------------------------------------------- 358
  355. 355. Slave 1 Slave 2 NORTH 4WD SMART CARS SOUTH 4WD SMART CARS Slave 3 Slave 4 359
  356. 356. partitions must match exactly 360
  357. 357. if not, better in 11g 361
  358. 358. fallback to bloom filter 362
  359. 359. SQL> select ... 2 from NORTH n, SOUTH s 3 where n.model = s.model ---------------------------------------------------------------- | Id | Operation | Name | Pstart| Pstop | ---------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | |* 1 | HASH JOIN | | | | | 2 | PART JOIN FILTER CREATE | :BF0000 | | | | 3 | PARTITION RANGE ALL | | 1 | 2 | | 4 | TABLE ACCESS FULL | NORTH | 1 | 2 | | 5 | PARTITION RANGE JOIN-FILTER| |:BF0000|:BF0000| | 6 | TABLE ACCESS FULL | SOUTH |:BF0000|:BF0000| ---------------------------------------------------------------- 363
  360. 360. if nececssary, brew your own don't assume 364
  361. 361. 365
  362. 362. wrap up 366
  363. 363. all positive 367
  364. 364. know the pitfalls 368
  365. 365. pitfalls # 1 369
  366. 366. SQL> select * from v$option; PARAMETER VALUE -------------------------------------------------- -------- Partitioning TRUE Objects TRUE Real Application Clusters TRUE Advanced replication TRUE Bit-mapped indexes TRUE Connection multiplexing TRUE Connection pooling TRUE Database queuing TRUE Incremental backup and recovery TRUE Instead-of triggers TRUE Parallel backup and recovery TRUE Parallel execution TRUE Parallel load TRUE 370
  367. 367. even in EE 372
  368. 368. worth the cost.... 373
  369. 369. pitfalls # 2 374
  370. 370. boundary cases constraint validation 375
  371. 371. boundary cases statistics gathering 376
  372. 372. boundary cases shared pool 377
  373. 373. boundary cases reference partitions 378
  374. 374. test with sql trace 379
  375. 375. Connor McDonald OracleDBA co.uk 380
  376. 376. ORA-00041 “active time limit exceeded - session terminated” www.oracledba.co.uk 381

×