connor mcdonald partitioning
DESCRIPTION
A look at the partitioning facilities all the way up 11gTRANSCRIPT
NOTE
itty bitty fonts in this
presentation
SQL> exec sample_font
Can you read this ?
1
Connor McDonald
OracleDBA
co
.uk
2
3
bio slide
4
Connor McDonald
6
why ?
7
...now
version 8.0
8
9
10
a personal history
11
80's
12
13
14
Walker Interactive
15
16
Jeff Walker...
20G
17
$200
per gigabyte
per month
19
Storage
is
expensive
20
21
Archive
22
90's
23
24
JBOD
25
26
Storage
is
cheap !
27
Archive
28
Archive
1992 1996 1999
30
00's
31
disk is even cheaper....
32
33
....but
34
36
keep everything !
37
JBOD
38
39
HBA
Infiniband
Filer
Cache
Fibre Channel
etc
40
Storage
is
cheap !
41
Storage
is
cheap !
Storage
is
expensive
42
CEO
brings us to today...
43
44
ILM
45
Lifecycle
Information
Management
46
keep everything .... cheaply
47
put the new stuff on good storage
put the old stuff on crappy storage
keep everything .... cheaply
48
split stuff up
49
50
basics
51
range partitioning
since 8.0
52
2009 2010 2011 2012
SALES
53
provocative statement
54
"all applications are (time)windows on data"
http://thehelsinkideclaration.blogspot.com/
55
corollary:
everyone can benefit
from range partitions
56
time the most common
57
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.
58
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'
range partition boundaries
59
60
split by upper bound
61
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
P02 >= 2010-01-01
P02 < 2010-02-01
62
possible benefits
63
performance
64
partition pruning
65
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 |
---------------------------------------------------------------
66
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'
67
more later...
68
dbms_xplan
69
SQL> explain plan for select ....
SQL> select *
2 from table(dbms_xplan.display)
70
SQL> select *
2 from table(
3 dbms_xplan.display(
4 format=>'PARTITION -COST -BYTES'));
71
SQL> select *
2 from table(dbms_xplan.display_awr(...))
72
SQL> select ...
SQL> select *
2 from table(dbms_xplan.display_cursor)
73
SQL> select *
2 from table(dbms_xplan.display_plan_baseline)
74
back to range partitioning
75
maintenance
add / drop
move
rebuild
backup / read-only
compress
cache control
76
availability
recovery
partition loss
a little dubious....
77
multi-column range
78
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.
79
tiebreaker
80
not multi dimension
81
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.
82
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 |
----------------------------------------------------------------
83
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 |
----------------------------------------------------------------------
84
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');
85
better in 11g
86
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)|
----------------------------------------------------------------------
87
hash partitioning
since 8.1
88
big stuff is a pain
89
"metapoor"
92
possible benefits
93
manageability
94
95
move
backup
etc
96
insertion
performance
97
"buffer busy waits"
98
"enq: HW - contention"
99
"read by other session"
100
101
less relevant nowadays
for tables
102
ASSM
103
automatic
segment
space
management
104
SQL> CREATE TABLESPACE DEMO
2 DATAFILE '...' SIZE 20G
3 EXTENT MANAGEMENT LOCAL
4 SEGMENT SPACE MANAGEMENT AUTO;
105
106
...but still very important
see later
107
SQL> create table T
2 ( x number(10) )
3 partition by hash ( x )
4 partitions 8
5 /
Table created.
108
even spread of values
109
SQL> create table T
2 ( x number(10) )
3 partition by hash ( x )
4 partitions 8
5 /
Table created.
SQL> insert into T
2 select level
3 from dual connect by level <= 100000
4 /
100000 rows created.
1,2,3,4 .... 100000
110
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
111
predicting hash target
remember these
112
SQL> select dbms_rowid.ROWID_OBJECT(rowid) ptn,
2 count(*)
3 from T
4 group by dbms_rowid.ROWID_OBJECT(rowid)
5 order by 2;
PTN COUNT(*)
---------- ----------
73535 12342
73536 12381
73538 12382
73534 12508
73532 12574
73533 12581
73531 12603
73537 12628
SQL> select ora_hash(x,7), count(*)
2 from t
3 group by ora_hash(x,7)
4 order by 2;
ORA_HASH(X,7) COUNT(*)
------------- ----------
4 12342
5 12381
7 12382
3 12508
1 12574
2 12581
0 12603
6 12628
113
the power of 2 rule
114
SQL> create table T
2 ( x number(10) )
3 partition by hash ( x )
4 partitions 4 | 8 | 16 | 32 ...
5 /
Table created.
115
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
116
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.
117
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
118
why ?
119
deliberately
for maintenance...
120
Task:
from 5 to 8 partitions
121
"classical" redistribution
122
"every" row moves
123
SQL> select count(*)
2 from T
3 where ora_hash(x,4) != ora_hash(x,7);
COUNT(*)
----------
87564
124
"smart" redistribution
125
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
5 rows selected.
pick one
126
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
127
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
128
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
129
only 1 partition "effort"
130
same for coalesce partition
131
handling a small number of values
132
range fiddly....
SQL> create table ...
...
20 values less than ('WB'),
21 values less than ('QLE'),
22 values less than ('SB'),
23 values less than ('VID'),
133
hash ... poor distribution
SQL> select state, ora_hash(state,7) hash
2 from AUST;
STATE HASH
----- ----
WA 2
SA 5
NSW 3
VIC 5
134
list
version 9
135
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.
136
think carefully on DEFAULT
add versus split
137
sometimes one level is not enough
138
139
140
ranges unevenly distributed
141
deletion of older data
20092010
2011 2012
142
composite partitions
143
composite (range + hash)
since 8.1
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 (
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)),
.....
145
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
146
long DDL .....
147
subpartition templates
148
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 ....
implicit
subpar's
149
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'
...
150
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
151
partitions
logical or physical
152
composite (range + list)
since 9
153
composite (anything + anything)
since 11
154
interval partitioning
11g
155
the problem with ranges....
156
... they are a range
157
require maintenance
158
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
25 PARTITION p13 VALUES LESS THAN
26 (TIMESTAMP' 2011-01-01 00:00:00')
27 );
159
insurance policy
160
SQL> insert into DEMO
2 values ( to_date('01-JAN-2014'), .... );
1 row created.
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
161
why MAXVALUE might hurt
(part 1)
162
split not add
163
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.
164
hoping for empty partition
165
"fast split" partition
166
index hassles
see later...
167
"solved" in 11g
168
169
interval partitioning
170
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.
171
partitions created as required
172
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'
173
gaps allowed
range partition boundaries
174
Length Length Length
175
partition name control lost
can rename....
176
convert range to interval
177
SQL> alter table DEMO
2 SET INTERVAL ( NUMTOYMINTERVAL(1,'MONTH') );
Table altered.
original range version
178
SQL> insert into DEMO
2 values ( to_date('01-JAN-2017'),....);
1 row created.
179
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'
180
but be careful ...
181
hybrid
range range range interval
182
is it range or interval ?
183
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 NUMBER
PARTITION_POSITION NUMBER
TABLESPACE_NAME 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)
?
184
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.
185
fixed in 11.2
186
high range value gets "stuck"
187
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.
188
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'
189
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
190
Length Length Length
191
workarounds (maybe) unpleasant....
192
SQL> alter table DEMO set interval ( );
Table altered.
SQL> alter table DEMO
2 set interval (NUMTOYMINTERVAL(1,'MONTH'));
Table altered.
193
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.
194
11.2
195
SQL> alter table DEMO
2 set interval (NUMTOYMINTERVAL(1,'MONTH'));
Table altered.
196
why MAXVALUE might hurt
(part 2)
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 (
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.
198
SQL> alter table DEMO
2 set interval ( NUMTOYMINTERVAL(1,'MONTH') );
*
ERROR at line 1:
ORA-14759: SET INTERVAL is not legal on this table.
199
explain plan anomaly
200
INTERVAL = "1 million partitions"
201
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.
202
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|
------------------------------------------------------------
203
partitioned tables ...
the bigger picture
204
2009 2010 2011 2012
SALES
SALES_ITEMS
SQL> desc SALES_ITEMS
Name Null? Type
-------------------- -------- -----------
SALE_ID NOT NULL NUMBER(12)
ITEM_ID NOT NULL NUMBER(12)
...
SQL> desc SALES
Name Null? Type
-------------------- -------- --------------
SALE_DATE NOT NULL DATE
...
205
reference partitions
11g
206
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.
207
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.
208
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.
209
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
210
seems good .... but
211
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
null
212
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
213
but the following "works"....
214
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
3 where table_name = 'PARENT';
PARTITION_NAME
------------------------------
SYS_P1196
P1
P2
P3
...
pk=-1
215
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
216
dropping requires order
217
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
218
its a very new feature
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
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.
219
Part 2
indexes on partitioned tables
220
221
2009 2010 2011 2012
SALES
SQL> create index SALES_IX on SALES ( CUSTOMER );
222
2009 2010 2011 2012
223
"global" index
224
big....really big
extended rowid
225
ILM issues
226
2009 2010 2011 2012
SQL> alter table SALES drop partition SALES_2009
227
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 | | |
---------------------------------------------------------------------
228
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 |
------------------------------------------------------------
229
SQL> select value
2 from v$parameter
3 where name = 'skip_unusable_indexes';
VALUE
------------------------------
TRUE
230
keep the index valid
231
2009 2010 2011 2012
SQL> alter table SALES drop partition SALES_2009
2 update indexes;
232
large delete
redo
undo
233
similar issues
merge
split
exchange
234
an alternative
235
"local" index
236
2009 2010 2011 2012
SQL> create index SALES_IX ON SALES ( CUSTOMER )
2 LOCAL;
237
smaller chunks
238
smaller rowid's
239
2009 2010 2011 2012
SQL> alter table SALES drop partition SALES_2009;
240
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
...
241
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
...
242
awesome for ILM
243
handlng old data
244
2009 2010 2011 2012
SQL> alter table SALES move partition SALES_2009
2 COMPRESS;
245
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;
RMAN
246
11.2 very cool
247
"segment-less" segments
248
2009 2010 2011 2012
SQL> alter index SALES_IX partition SALES_IX_2009
2 UNUSABLE;
249
handlng new data
250
2010 2011 201220132013
SQL> alter table SALES exchange
2 partition SALES_2013 with
3 table NEW_SALES;
local = goodlocal = good
252
global = badglobal = bad
253
NO !
254
different "target audience"
255
2009 2010 2011 2012
SQL> select *
2 from SALES
3 where CUSTOMER = 123;
123 123 123 123
SQL> create index SALES_IX on SALES ( CUSTOMER ) LOCAL;
256
can be much much worse...
257
2009 2010 2011 2012
SQL> select *
2 from SALES
3 where CUSTOMER = 123;
WA VIC
NSW QLD
WA VIC
NSW QLD
WA VIC
NSW QLD
WA VIC
NSW QLD
258
explain plan
259
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 |
----------------------------------------------------------------------
260
2009 2010 2011 2012
SQL> select *
2 from SALES
3 where CUSTOMER = 123;
123123123123
SQL> create index SALES_IX on SALES ( CUSTOMER ) LOCAL;
261
"so global forindex lookups then"....
262
NO !
263
2009 2010 2011 2012
SQL> select *
2 from SALES
3 where CUSTOMER = 123
4 and YEAR = 2010;
123
264
careful design
265
application compromises
eg unique keys
266
so far ... "equipartition"
267
SALES
SQL> create index SALES_IX ON SALES ( CUSTOMER )
2 global
3 partition by ....
268
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.
269
rare ....
270
...one special case
10g+
271
hash partitioned index
272
recall: hash partitioned tables
273
concurrencyASSM
274
indexes a problem
275
276
hash partitioned indexes
277
SQL> create index SALES_PK on SALES( TXN_ID )
2 global partition by hash ( TXN_ID )
3 partitions 8
4 /
Index created.
278
279
only for equality
primary keys
280
beware the NOSORT
281
reference partitions and indexes
282
2009 2010 2011 2012
2009 2010 2011 2012
SALES
SALES_ITEMS
283
take care with ILM
284
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
285
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
286
SQL> select index_name, status from user_indexes;
INDEX_NAME STATUS
------------------------------ --------
PARENT_PK UNUSABLE
CHILD_PK UNUSABLE
287
exchange is difficult...
288
plus more restrictions.....
289
Part 3
partition queries
290
partition pruning
291
efficiency =
data required /
data scanned
292
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.
293
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.
360 days
294
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 |
---------------------------------------------------------------
295
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 |
------------------------------------------------------------
296
static versus dynamic
297
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 |
---------------------------------------------------------------
298
lots of power
varies by version
299
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)|
-----------------------------------------------------------
300
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) |
---------------------------------------------------------------
301
limitations of explain plan
302
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
303
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
July
304
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:\ORACLE\DB11\USERS01.DBF'
305
"NO OP" pruning
306
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|
--------------------------------------------------------------
307
pruning lists
308
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.
309
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 |
---------------------------------------------------------------
310
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 |
---------------------------------------------------------------
311
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 |
------------------------------------------------------------
312
pruning composites
313
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 ....
314
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 |
---------------------------------------------------------------
315
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 |
---------------------------------------------------------------
316
pruning by subquery
317
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)|
-------------------------------------------------------------------
11g
318
maybe 10.2 ?
319
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|
-----------------------------------------------------------------
320
| 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 ?
bloom filters
321
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
323
wtf ?
324
"b" bits
"h" hash functions
325
b0
b1
b2
b3
b4
b5
b6
b7
h1
h2
h3
data
326
b0
b1
b2
b3
b4
b5
b6
b7
h1
h2
h3
data
327
b0
b1
b2
b3
b4
b5
b6
b7
h1
h2
h3
data
328
b0
b1
b2
b3
b4
b5
b6
b7
h1
h2
h3
data
329
b0
b1
b2
b3
b4
b5
b6
b7
h1
h2
h3
data
330
b0
b1
b2
b3
b4
b5
b6
b7
h1
h2
h3
matching
data?
331
b0
b1
b2
b3
b4
b5
b6
b7
h1
h2
h3
matching
data?
do the
"real"
work
332
b0
b1
b2
b3
b4
b5
b6
b7
h1
h2
h3
matching
data?
do the
"real"
work
333
"meta-poor"
334
335
336
"are you joking...try in 6 months"
337
"yes, we have some"
338
339
false positives possible
340
false negatives impossible
341
they are here to stay....
342
SQL> alter session set "_bloom_filter_enabled" = false;
SQL> alter session set "_bloom_pruning_enabled" = false;
343
other partitioning benefits
344
partition wise join
345
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 |
-------------------------------------------------------------
346
"big deal"
347
meta-poor
348
349
1000 cars north of Perth
1000 cars south of Perth
350
351
"replace damaged modelsat the north yard with matching
models from the south yard"
352
353
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 |
----------------------------------------------------------------
354
NORTH
SOUTH
4WD SMART CARS
4WD SMART CARS
355
partition wise join
356
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 |
-------------------------------------------------------------
357
great parallel benefits
358
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 | |
----------------------------------------------------------------------------------------------
359
NORTH
SOUTH
4WD SMART CARS
4WD SMART CARS
Slave 1 Slave 2
Slave 3 Slave 4
360
partitions must match exactly
361
if not, better in 11g
362
fallback to bloom filter
363
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|
----------------------------------------------------------------
364
if nececssary, brew your own
don't assume
365
wrap up
366
all positive
367
know the pitfalls
368
pitfalls # 1
369
370
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
even in EE
372
worth the cost....
373
pitfalls # 2
374
boundary cases
375
constraint validation
boundary cases
376
statistics gathering
boundary cases
377
shared pool
boundary cases
378
reference partitions
test with sql trace
379
Connor McDonald
OracleDBA
co
.uk
380
381
ORA-00041
www.oracledba.co.uk
“active time limit exceeded - session terminated”