Connor McDonald Partitioning

Post on 27-Jan-2015

137 views 4 download

Tags:

description

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

Transcript of Connor McDonald Partitioning

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”