Title: Partitioning The Part is Better than the Whole
1Partitioning The Part is Better than the Whole
www.ntirety.com
LAOUG Thursday, February 21, 2008
Michael S. Abbey Database Officer Oracle
Practice
2Agenda
- Partitioning advantages
- Partitioning existing objects
- Naming conventions
- What's new with 10g
- Partitioned indexesa global problem
- Tips and Tricks
3Advantages
- Large objects can be treated as a collection of
small objects - multi-million row tables are impossible to manage
- statistic collection using partnamegt feature
- smaller logical objects influence execution plans
- Housekeeping done now rather than later
- Pro-active rather than re-active
- Partition-wise joins
4Advantages
- Partition pruning
- queries that use partition key columns in
predicate - treats a huge partitioned table as a handful of
smaller counterparts - DBMS_STATS
- global vs. partition-level
- decisions made a run time
- Partition maintenance need not affect whole table
5Planning
- Candidates
- Multi-million row tables
- Multi-gigabyte or terabyte tables
- Fat tables with hundreds of thousands of rows
- Should all the data be partitioned
- Opportunity for archival at the same time
- Selection of a partition key
- Be prepared
6Planning
- Range is most common and lends itself the best to
archival - List available in 9 and 10, adds some complexity
to partition maintenance - Hash is the best for equal row distribution and
requires the least maintenance requirements - Composite is a mixture of range and hash / list
and hash
7Partitioning Existing Objects
- Excuses
- I don't have EE (show stopper!)
- I don't know how ... September 24, 2007
- I cannot afford the hours of down time ... not
necessary using materialized views - I don't have the rollback or disk space for all
the redo - Big objects are a headache ... and they are only
getting bigger
8Choosing a partition key
- Way the data is retrieved by your applications
- Way existing unique indexes are setup
- partition key column(s) must exist in a
partitioned local unique index - table partitioned on id
- id must exist in unique index (using index with
PK) - global unique indexes must be prefixed
- table partitioned on column1
- global unique index must start with column1
- Try to use a single column whenever possible
9Choosing a partition key
- Columns cannot be modified once the partitioning
is done - Expand the size of number and varchar2 columns
prior to partitioning - Archival possibilities/requirements affect choice
- Impact of a multi-column partition key
- Unique index syntax requirements
Invest the time now
10Partition boundaries
Choice of boundaries for partitions when
partitioning an existing table numeric partition
key.
Goal
- Use imbedded functionality of optimizer
histograms - Table has 35,689 rows
- Partitioning key column is number
- Target is equal row distribution
11Partition boundaries
SQLgt begin 2 dbms_stats.gather_table_stats
(ownnamegt'OPSORACLE', 3
tabnamegt'SALE', 4
estimate_percentgt10, 5
method_optgt'for all indexed columns size 8')
6 end 7 / PL/SQL procedure successfully
completed.
- estimate_percent studies have shown small values
are desirable - value of buckets may need tweaking to achieve goal
12Partition boundaries
SQLgt select endpoint_value from
user_tab_histograms 2 where table_name
'SALE' ENDPOINT_VALUE --------------
10007 598856809 598861376
598866106 598870484 758155561
2103623867 3577981994 4998662814 9 rows
selected.
13Partitioned counterpart
SQLgt create table sale_p ( 2 id
number, 3 cust_id number, 4 quantity
number) 5 partition by range (id) 6
(partition sale_p001 values less than
(598856809), 7 partition sale_p002 values
less than (598861376), 8 partition sale_p003
values less than (598866106), 9 partition
sale_p004 values less than (598870484), 10
partition sale_p005 values less than
(758155561), 11 partition sale_p006 values
less than (2103623867), 12 partition sale_p007
values less than (3577981994), 13 partition
sale_p008 values less than (4998662814) 14
partition sale_p009 values less than
(5300000000)) Table created. SQLgt SQLgt alter
table sale_p add constraint sale_p_pk 2
primary key (id) using index local Table
altered.
14The materialized view
SQLgt create snapshot sale_p on prebuilt table 2
refresh fast start with sysdate 3 next
sysdate1/24 4 as select from
sale Materialized view created. SQLgt begin 2
dbms_snapshot.refresh('SALE_P','C') 3 end
4 / PL/SQL procedure successfully completed.
15Sanity check
SQLgt select count() from sale
COUNT() ---------- 35689 1 row
selected. SQLgt select count() from sale_p
COUNT() ---------- 35689 1 row selected.
16Additional indexes
- to match SALE non-partitioned
- global index on CUST_ID
- non-partitioned index on QUANTITY
- building immediately
- saves time during cutover
- renaming code can be pre-created
- run DBMS_STATS now
- consistency and completeness check at your
leisure (e.g., column defaults and check
constraints)
17Additional indexes
SQLgt create index sale_p_n1 on sale_p (cust_id)
2 global partition by range (cust_id) 3
(partition sale_p_n1_p001 values less than (40),
4 partition sale_p_n1_p002 values less than
(90), 5 partition sale_p_n1_p003 values less
than (600), 6 partition sale_p_n1_pmax values
less than (maxvalue)) Index created. SQLgt
create index sale_p_n2 on sale_p
(quantity) Index created.
18The cutover
- negotiate an acceptable time
- quiesce applications
- drop snapshot on prebuilt table
- drop snapshot log on SALE
- drop indexes on SALE
- norows export on SALE
- rename SALE and SALE_P
- import into partitioned SALE
19Snapshot work
SQLgt drop snapshot sale_p Materialized view
dropped. SQLgt drop snapshot log on
sale Materialized view log dropped. Table
altered.
20Drop indexes on SALE
SQLgt drop index sale_n1 Index dropped. SQLgt
drop index sale_n2 Index dropped. SQLgt alter
table sale drop constraint sale_pk Table
altered.
21No rows export
/oraclegt exp userid/ rowsn tablessale
filesale statisticsnone Export Release
9.2.0.7.0 - Production on Wed Feb 30 094822
2009 ... ... Note table data (rows) will not be
exported ... ... About to export specified tables
via Conventional Path ... . . exporting table
SALE Export terminated
successfully with warnings.
22Important Points
- expand partition key column
- alter table sale modify id number(8)
- manual complete refresh required to kickstart the
snapshot job - secondary index creation time must be factored
into the cutover if not created with snapshot - must (should) use DBMS_STATS rather than ANALYZE
23Naming Conventions
- 30 characters
- self-explanatory
- formulation is great gt adoption is better
- data dictionary familiarity
- user_tabind_subpartitions
- user_part_tablesindexes
- PARTITION_POSITION is the most important column
24Naming conventions worst enemy
Partition maintenance ...
25Naming ConventionsTables
- table name
- partition number
- appropriate left zero padding so all partition
numbers are the same length - overestimate in case many new partitions required
- partition or subpartition
- separated by underscores
- creative abbreviation approach
- identify hash partitions with HP
26SALE
SQLgt alter table sale split partition sale_pmax
at (90) Table altered. SQLgt select
partition_name from user_tab_partitions PARTITIO
N_NAME ------------------------------ SYS_P1 SYS_P
2 SALE_P001 SALE_P002 SALE_P003 SALE_P004 SALE_P00
5 SALE_P006 SALE_P007 9 rows selected.
27Fixing partition names
SQLgt select 'alter table sale rename partition
' 2 partition_name' to sale_p'
3 lpad(partition_position,3,'0')'' 4
from user_tab_partitions 5 where
table_name 'SALE' alter table sale rename
partition SYS_P1 to sale_p008 alter table sale
rename partition SYS_P2 to sale_p009 alter table
sale rename partition SALE_P001 to
sale_p001 alter table sale rename partition
SALE_P002 to sale_p002 alter table sale rename
partition SALE_P003 to sale_p003 alter table
sale rename partition SALE_P004 to
sale_p004 alter table sale rename partition
SALE_P005 to sale_p005 alter table sale rename
partition SALE_P006 to sale_p006 alter table
sale rename partition SALE_P007 to sale_p007
28Fixing partition names
SQLgt alter table sale rename partition SALE_P007
to sale_p007 alter table sale rename partition
SALE_P007 to sale_p007
ERROR at line 1 ORA-14081
new partition name must differ from the old
partition name SQLgt select 'alter table
sale rename partition ' 2
partition_name' to sale_p' 3
lpad(partition_position,3,'0')'' 4 from
user_tab_partitions 5 where table_name
'SALE' 6 and partition_name not like
'SALE_P' alter table sale rename partition
SYS_P1 to sale_p008 alter table sale rename
partition SYS_P2 to sale_p009
29Fixing partition names
SQLgt select 'alter table sale rename partition
' 2 partition_name' to sale_pmax'
3 from user_tab_partitions 4 where
table_name 'SALE' 5 and
partition_position 6 (select
max(partition_position) 7 from
user_tab_partitions 8 where table_name
'SALE') alter table sale rename partition
SALE_P009 to sale_pmax
- do not QUIT until naming convention is 100
followed - there is almost always a better way to do it
30Fixing partition names
SQLgt alter table sale split partition sale_pmax
at (90) into 2 (partition sale_p008,partition
sale_pmax) Table altered. SQLgt select
partition_name 2 from user_tab_partitions 3
where table_name 'SALE' 4 order by
partition_position SALE_P001 SALE_P002 SALE_P003
SALE_P004 SALE_P005 SALE_P006 SALE_P007 SALE_P008
SALE_PMAX
31SALE
SQLgt alter table sale add partition
sale_p20060331 2 values less than 3
(to_date('01-APR-2006','DD-MON-YYYY')) Table
altered. SQLgt select partition_name from
user_tab_partitions 2 where table_name
'SALE' SALE_P20040331 SALE_P20040630 SALE_P200409
30 SALE_P20041231 SALE_P20050331 SALE_P20050630 SA
LE_P20050930 SALE_P20051231 SALE_P20060331
32SALE
create table sale (id date, ...
varchar2(32)) partition by hash (id) partitions 4
33Fixing partition names
SQLgt select 'alter table sale rename partition
' 2 partition_name' to sale_hp'
3 lpad(partition_position,3,'0')'' 4
from user_tab_partitions 5 where
table_name 'SALE' alter table sale rename
partition SYS_P212 to sale_hp001 alter table
sale rename partition SYS_P213 to
sale_hp002 alter table sale rename partition
SYS_P214 to sale_hp003 alter table sale rename
partition SYS_P215 to sale_hp004
34Adding to SALE
SQLgt alter table sale add partition Table
altered. SQLgt alter table sale add
partition Table altered. SQLgt alter table sale
add partition Table altered. SQLgt alter table
sale add partition Table altered.
SQLgt select partition_name 2 from
user_tab_partitions 3 where table_name
'SALE' SYS_P7 SYS_P8 SYS_P3 SYS_P4 SYS_P5 SYS_P6
SYS_P9 SYS_P10
35Fixing partition names
SQLgt select 'alter table sale rename partition
' 2 partition_name' to sale_hp'
3 lpad(partition_position,3,'0')'' 4
from user_tab_partitions 5 where
table_name 'SALE' alter table sale rename
partition SYS_P7 to sale_hp005 alter table sale
rename partition SYS_P8 to sale_hp006 alter
table sale rename partition SYS_P3 to
sale_hp001 alter table sale rename partition
SYS_P4 to sale_hp002 alter table sale rename
partition SYS_P5 to sale_hp003 alter table sale
rename partition SYS_P6 to sale_hp004 alter
table sale rename partition SYS_P9 to
sale_hp007 alter table sale rename partition
SYS_P10 to sale_hp008
36Naming ConventionsIndexes
- Can prove more difficult to stay in the 30
character limit - 3 part nomenclature
- Table name (e.g., SALE_)
- Index type and sequence
- n1 n2 n3
- u1 u2 u3
- f1 f2 f3
- Partition number
- Creative abbreviation required
37Naming ConventionsIndexes
range list
hash
38Naming ConventionsIndexes
- SALE_N2_P001_HSP004
- SALE_F1_P002_SP008
- SALE_N5_HP002
- SALE_U3_P003_L003
39Whats new in 10g
40What's New in 11g
41What's New in 11g
http//www.oracle.com/solutions/business_intellige
nce/partitioning.html
42Indexes
Goal
Understand ramifications of partition splitting.
- invalid indexes and unusable index partitions is
the nature of the beast if not local - only way to add to a table that uses maxvalue
- keep ahead of yourself allowing no less than 2
empty partitions before last - can avoid invalidating index components
- Empty partitions valid and usable indexes
-
43Splitting pmax
SQLgt alter table sale split partition sale_pmax
at (9101000000) 2 into (partition sale_p010,
partition sale_pmax) Table altered. SQLgt SQLgt
select partition_name,index_name,status 2
from user_ind_partitions PARTITION_NAME
INDEX_NAME STATUS ---------------- -----------
-------- SALE_P010 SALE_PK
UNUSABLE SALE_PMAX SALE_PK
UNUSABLE SALE_P001 SALE_PK
USABLE ... ... 11 rows selected.
Must be rebuilt
44Splitting pmax
SQLgt select from sale partition (sale_pmax)
ID CUST_ID QUANTITY ----------
---------- ---------- 9101000000 12
31 9101010000 12 31 SQLgt
select from sale partition (sale_p010)
ID CUST_ID QUANTITY ---------- ----------
---------- 9100000000 12 31
45Splitting affect
- If there are rows in the 2 partitions after the
split - global index partitions unusable
- non-partitioned indexes invalid
- local index partitions involved in the split
unusable, others still fine - No rows in 1 or both partitions should not
invalidate any indexes or index partitions - USER_INDEXES, USER_IND_PARTITIONS,
USER_IND_SUBPARTITIONS
46Invalid/unusable
47Best practice
SQLgt select count() from sale partition
(sale_p001) 4599 SQLgt select count()
from sale partition (sale_p002) 4567 SQLgt
select count() from sale partition (sale_p003)
4730 SQLgt alter table sale drop partition
sale_p001 Table altered.
48Best practice
SQLgt select partition_name,status from 2
user_ind_partitions order by 1 SALE_P002
USABLE SALE_P003
USABLE SALE_P004
USABLE SALE_P005
USABLE SALE_P006
USABLE SALE_P007
USABLE SALE_P008
USABLE SALE_P009
USABLE SALE_P010A
USABLE SALE_P010B
USABLE SALE_PMAX USABLE 11
rows selected. SQLgt select index_name,status
from user_indexes SALE_N1
UNUSABLE SALE_PK N/A
49Best practice
SQLgt alter index sale_n1 rebuild Index
altered. SQLgt alter table sale truncate
partition sale_p002 Table truncated. SQLgt
alter table sale drop partition sale_p002 Table
altered.
50Best practice
SQLgt select index_name,status from
user_indexes SALE_N1
UNUSABLE SALE_PK N/A SQLgt
select partition_name,status from
user_ind_partitions 2 order by 1 SALE_P003
USABLE SALE_P004
USABLE SALE_P005
USABLE SALE_P006
USABLE SALE_P007
USABLE SALE_P008
USABLE SALE_P009
USABLE SALE_P010A
USABLE SALE_P010B
USABLE SALE_PMAX USABLE 10
rows selected.
51Best practice
SQLgt alter index sale_n1 rebuild Index
altered. SQLgt delete sale partition
(sale_p003) 4730 rows deleted. SQLgt alter
table sale drop partition sale_p003 Table
altered. SQLgt select index_name,status from
user_indexes SALE_N1
VALID SALE_PK N/A
52Best practice
SQLgt select partition_name,status 2 from
user_ind_partitions 3 order by 1 SALE_P004
USABLE SALE_P005
USABLE SALE_P006
USABLE SALE_P007
USABLE SALE_P008
USABLE SALE_P009
USABLE SALE_P010A
USABLE SALE_P010B
USABLE SALE_PMAX USABLE 9
rows selected.
53Hash partitioned indexes
- Always invalidated by maintenance activities
- Partitions assume system-generated names at
creation time
SQLgt alter table sale add constraint sale_pk
primary key 2 (id) using index local Table
altered. SQLgt SQLgt select partition_name,index_n
ame from user_ind_partitions SYS_P53
SALE_PK SYS_P54
SALE_PK SYS_P55
SALE_PK SYS_P56 SALE_PK 4
rows selected.
54Fix hash partition index names
SQLgt select 'alter index 'index_name' rename
partition ' 2 partition_name' to
'index_name'_HP' 3
lpad(partition_position,3,'0') 4 from
user_ind_partitions alter index SALE_PK rename
partition SYS_P53 to SALE_PK_HP001 alter index
SALE_PK rename partition SYS_P54 to
SALE_PK_HP002 alter index SALE_PK rename
partition SYS_P55 to SALE_PK_HP003 alter index
SALE_PK rename partition SYS_P56 to SALE_PK_HP004
55Add hash partitions
SQLgt alter table sale add partition Table
altered. SQLgt alter table sale add
partition Table altered. SQLgt alter table sale
add partition Table altered. SQLgt alter table
sale add partition Table altered.
56Table partition names
SQLgt select 'alter table sale rename partition
'partition_name 2 ' to sale_hp'lpad(part
ition_position,3,'0') 3 from
user_tab_partitions alter table sale rename
partition SYS_P85 to sale_hp005 alter table sale
rename partition SYS_P86 to sale_hp006 alter
table sale rename partition SYS_P81 to
sale_hp001 alter table sale rename partition
SYS_P82 to sale_hp002 alter table sale rename
partition SYS_P83 to sale_hp003 alter table sale
rename partition SYS_P84 to sale_hp004 alter
table sale rename partition SYS_P87 to
sale_hp007 alter table sale rename partition
SYS_P88 to sale_hp008 8 rows selected.
57Index partition names
SQLgt select 'alter index 'index_name' rename
partition ' 2 partition_name' to
'index_name'_hp' 3 lpad(partition_positio
n,3,'0') 4 from user_ind_partitions alter
index SALE_PK rename partition SYS_P81 to
SALE_PK_hp001 alter index SALE_PK rename
partition SYS_P85 to SALE_PK_hp005 alter index
SALE_PK rename partition SYS_P86 to
SALE_PK_hp006 alter index SALE_PK rename
partition SYS_P87 to SALE_PK_hp007 alter index
SALE_PK rename partition SYS_P82 to
SALE_PK_hp002 alter index SALE_PK rename
partition SYS_P83 to SALE_PK_hp003 alter index
SALE_PK rename partition SYS_P84 to
SALE_PK_hp004 alter index SALE_PK rename
partition SYS_P88 to SALE_PK_hp008 8 rows
selected.
58Tips and Tricks Summary
- Make partition names self explanatory
- Use materialized views with fast refresh for
close to zero downtime partitioning of existing
tables - Let export (no rows) or data pump (metadata_only)
complete the cycle - Keep last few partitions of range-based tables
emptymonitor and report their contents regularly
59(No Transcript)
60Contact information
michael.abbey_at_ntirety.com
fenderpbs