Skip to Main Content
  • Questions
  • Can I change a range-partitioned table to a composite partitioned table?

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question.

Asked: April 17, 2003 - 3:05 pm UTC

Last updated: February 22, 2007 - 8:33 am UTC

Version: 8.1.7

Viewed 1000+ times

You Asked

I need to change a huge table of >60ml rows to a partitioned table. It has data from 1998 to 2003, but data for 1998, 1999, 2000 are few so I want to combine them with data of 2001 to become 1 partition. data for 2002 is the biggest, and data for 2003 is obviously also going toward that direction. So ideally I would want to subpartition 2002 and 2003 by hash. Here is what I did:

rename old_event to old_event_table;

CREATE TABLE old_event
PCTFREE 10
TABLESPACE dbridge_l
PARTITION BY RANGE (oe_ent_date)
(PARTITION oe_all VALUES LESS THAN (TO_DATE('01-Jan-2004', 'dd-Mon-yyyy')),
PARTITION oe_since2004 VALUES LESS THAN (MAXVALUE))
AS (SELECT * FROM OLD_EVENT_TABLE WHERE 1 = 0);


ALTER TABLE old_event
EXCHANGE PARTITION oe_all
WITH TABLE old_event_table
WITHOUT VALIDATION;


ALTER TABLE old_event
SPLIT PARTITION oe_all AT (TO_DATE('01-Jan-2002', 'dd-Mon-yyyy')) INTO
(PARTITION oe_before2002, PARTITION oe_20022003);


ALTER TABLE old_event
SPLIT PARTITION oe_20022003 AT (TO_DATE('01-Jan-2003', 'dd-Mon-yyyy')) INTO
(PARTITION oe_2002, PARTITION oe_2003);

So by now the partition level is achieved. Can I create subpartition at this stage, or this has to be done at create table stage, namely, the create table statement should be:

CREATE TABLE old_event_file
PCTFREE 10
TABLESPACE dbridge_l
PARTITION BY RANGE (oe_ent_date)
--------------------------------------------
SUBPARTITION BY HASH (MODE) SUBPARTITIONS 8
--------------------------------------------
(PARTITION oe_all VALUES LESS THAN (TO_DATE('01-Jan-2004', 'dd-Mon-yyyy')),
PARTITION oe_since2004 VALUES LESS THAN (MAXVALUE))
AS (SELECT * FROM OLD_EVENT_TABLE WHERE 1 = 0);

If I do this, what would happen when I later split each partition? What about if I don't want subpartition in some of the smaller partitions? So basically, seems we can't change a range-partitioned table into a composite one?

Also during the splitting, I noticed it required about the same number of temporary segments with the original number of segments so in this case it is big space requirement, it also generates lots of redo. Do you think this is the best way of changing a big non-partitioned table into a partitioned one?

Thanks so much for your help, as always!

and Tom said...

subpartitioning is something you need to do at table create time. We can achieve your goals, just not the way you tried. Consider, we'll start with a table with a single (low) partition and a single subpartition -- we need to START with a composite partitioned table:



ops$tkyte@ORA920> create table new_table
2 (OWNER VARCHAR2(30),
3 OBJECT_NAME VARCHAR2(30),
4 SUBOBJECT_NAME VARCHAR2(30),
5 OBJECT_ID NUMBER,
6 DATA_OBJECT_ID NUMBER,
7 OBJECT_TYPE VARCHAR2(18),
8 CREATED DATE,
9 LAST_DDL_TIME DATE,
10 TIMESTAMP VARCHAR2(19),
11 STATUS VARCHAR2(7),
12 TEMPORARY VARCHAR2(1),
13 GENERATED VARCHAR2(1),
14 SECONDARY VARCHAR2(1)
15 )
16 partition by range ( CREATED )
17 subpartition by hash(object_id) subpartitions 1
18 ( partition part1 values less than ( to_date( '01-jan-2003', 'dd-mon-yyyy' ) )
19 )
20 /

Table created.

Now, we can easily make it so additional partitions all have 8 subpartitions:

ops$tkyte@ORA920> alter table new_table set subpartition template 8;

Table altered.

ops$tkyte@ORA920>
ops$tkyte@ORA920> alter table new_table add partition part2 values less than ( to_date('01-jan-2004', 'dd-mon-yyyy' ) );

Table altered.

ops$tkyte@ORA920> alter table new_table add partition part3 values less than ( to_date('01-jan-2005', 'dd-mon-yyyy' ) );

Table altered.

and if you decide part3 should have even MORE then part2, just add more manually

ops$tkyte@ORA920>
ops$tkyte@ORA920>
ops$tkyte@ORA920> alter table new_table modify partition part3 add subpartition;

Table altered.

ops$tkyte@ORA920> alter table new_table modify partition part3 add subpartition;

Table altered.

ops$tkyte@ORA920> alter table new_table modify partition part3 add subpartition;

Table altered.

ops$tkyte@ORA920> alter table new_table modify partition part3 add subpartition;

Table altered.

ops$tkyte@ORA920> alter table new_table modify partition part3 add subpartition;

Table altered.

ops$tkyte@ORA920> alter table new_table modify partition part3 add subpartition;

Table altered.

ops$tkyte@ORA920> alter table new_table modify partition part3 add subpartition;

Table altered.

ops$tkyte@ORA920>
ops$tkyte@ORA920> select partition_name, subpartition_count
2 from user_tab_partitions
3 where table_name = 'NEW_TABLE';

PARTITION_NAME SUBPARTITION_COUNT
------------------------------ ------------------
PART1 1
PART2 8
PART3 15

then, bulk load the table this way:


ops$tkyte@ORA920> alter table new_table NOLOGGING;
Table altered.

ops$tkyte@ORA920> set autotrace on statistics;
ops$tkyte@ORA920> insert /*+ append */ into new_table select * from all_objects;

31622 rows created.


Statistics
----------------------------------------------------------
1248 recursive calls
870 db block gets
106096 consistent gets
57 physical reads
64692 redo size
775 bytes sent via SQL*Net to client
830 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
13 sorts (memory)
0 sorts (disk)
31622 rows processed

ops$tkyte@ORA920> set autotrace off
ops$tkyte@ORA920> alter table new_table logging;
Table altered.

backup and you are done.





Rating

  (10 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Brilliant - rating is 6 stars

Marc, April 18, 2003 - 12:34 am UTC

Never seen set subpartition template 8 before.

Thanks Tom

add partitions

lakshmi, April 18, 2003 - 6:56 am UTC

excellent !!!!

Great!

A reader, April 18, 2003 - 9:22 am UTC

It also corrected a misconception I brought back from a training class: that you always have to have >1 partition in a table or >1 subpartion in a partition. Of course I didn't try to break that myself! I think conceptually it doesn't make much sense (to have just 1 part in a table), but it can be a starting point, just as in this case it is used to set up a structure for adding more.

Tom Kyte
April 18, 2003 - 12:27 pm UTC

conceptually it can be very COOL to have a single partition table.

Suppose....

every month, you get new data.
you load it into stage
you scrub it
you want to replace existing data in database with it.


you could:

rename old + rename new to old -- but that is two statements, chance of failure between the two and they are not "transactional"

drop old + rename new to old -- same problem.

recreate a synonym (viable)
recreate a view (viable)

alter table exchange partition with table -- viable as well, just swap the data from the stage table with the existing data and be done with it.

alter table xxx set subpartition template xx

A reader, April 18, 2003 - 10:22 am UTC

Seems this is only available in 9i!

Tom Kyte
April 18, 2003 - 12:36 pm UTC

sorry about that -- but the adding of subpartions will in fact work -- just a little more "manual"

alter table new_table set subpartition template 8
*
ERROR at line 1:
ORA-02000: missing UNUSED keyword



Table altered.


Table altered.


Table altered.


Table altered.


PARTITION_NAME SUBPARTITION_COUNT
------------------------------ ------------------
PART1 1
PART2 1
PART3 3





Variable number of subpartitions

A reader, April 18, 2003 - 11:34 am UTC

So far, I was under the impression that all the partitions should have the same number of sub-partitions.

Well, Tom proved I was wrong. Every time I open up asktom.oracle.com, I learn something new.

Great forum

subpartitions 1

Ernani, June 24, 2003 - 5:12 pm UTC

Now, I know that a partition can have only 1 subpartition!

Great Example

Jimr, June 29, 2005 - 2:54 pm UTC

This is absolutely great - exactly what I needed to do.

Grrr.

Mark Brady, February 21, 2007 - 1:59 pm UTC

But why? Why does Subpartitioning have to be defined at create time? Is this something that should be/will be done but they just couldn't get it done for release or is there some kind of technological objection to splitting a partition into 2 subpartitions rather than two partition?

I'm not asking you to speak for or defend the development team, just curious.

This limitation seems artificial and is definitly creating useless work.
Tom Kyte
February 21, 2007 - 3:27 pm UTC

because it is a physical structure sort of thing. You have tables without partitions. In order to partition - you rebuild.

You have partitioned tables without subpartitions.

In order to subpartition - you rebuild.

the data needs to "move"

Now, if all of the data in your current "partition" would go into a single "subpartition" you can:

a) exchange full partitions with empty tables
b) recreate table with partitions and subpartitions
c) exchange full tables with empty subpartitions



Why can't I give more than 5 stars

Mark Brady, February 21, 2007 - 4:59 pm UTC

Superlatives fail. What a great idea. The comparsion between non-partitioned and partitioned tables is also extremely apt. read: I get it.

I was just looking at your PPT from Hotsos last year and you mentioned Enhanced Online Table Redefinition. I was about to consider that before reading this.

The table is around 20gb and has about 400 partitions. Which would you choose and why? Obviously I'd automate the part-table swap, table-subpart swap. This would necessitate downtime? Which we have on weekends.


Wait one...

Mark Brady, February 21, 2007 - 6:21 pm UTC

The solution is still a great one, very excited about it, but the answer about why i can't subpartition after creation is nagging me.


I can both split and merge partitions and subpartitions. Those are physical storage changes. Data has to "move". We can have data constantly moving between partitions if we ENABLE ROW MIGRATION.

I could make every partitioned table a subpartitioned table at design time with one subpart and default as the list. The only hitch is that I'd have to anticipate the subpartition key.

This command already exists:

ALTER TABLE all_seasons SPLIT PARTITION quarter_1
AT (TO_DATE('16-dec-1997','dd-mon-yyyy'))
INTO (PARTITION q1_1997_1 SUBPARTITIONS 4 STORE IN (ts1,ts3),
PARTITION q1_1997­_2);

The only difference between this command and what I'd like is that you'd have to specify the key and then the template subparts would get applied to every partition.

ALTER TABLE all_seasons SPLIT PARTITION ALL
AT (state_cd) INTO
(SUBPARTITION northern VALUES ('NY', 'VT'),
SUBPARTITION southern VALUES ('FL', 'AL'));

Heck you could add ERRORS INTO clause to send 'VA' records somewhere else instead of failing.

Or one partition at a time with some table level statement that would just set the KEY

ALTER TABLE all_seasons SET SUBPARTITION KEY AS (column1, ...);

Then you could run my ALTER for each partition individually.



In any event, I don't buy that spliting a partition into 2 partitions is any different than spliting it into 1 partition with 2 subpartitions. Besides the added complexity of handling the key definition - which is only logical. Under the covers I get the same thing.

Tom Kyte
February 22, 2007 - 8:33 am UTC

you are changing the fundamental physical structure of the table - the fundamental structure.

that is all. You are changing the fundamental structure of the table. Not just taking a table full of partitions and splitting a partition (you had a partitioned table, you still have a partitioned table)

subpartitioning is a radical change. That is all.

More to Explore

VLDB

If you are new to partitioning, check out Connor McDonald's introduction series here.

VLDB

Documentation set on VLDB and Partitioning.