Skip to Main Content
  • Questions
  • How to create recurring sub partitions for 12 months based on a date field?

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, K.

Asked: July 30, 2019 - 10:38 am UTC

Last updated: July 31, 2019 - 4:14 pm UTC

Version: Oracle Database 12c Enterprise Edition Release 12.2.0.1.0

Viewed 1000+ times

You Asked

Dear Oracle Team,

I have a table which has 2 important columns one for the year and another with date. Since the volume of the table is very high, we are planning to partition the table based on the year column which is a number(4) type and sub-partition by month using the Date field.

I understood from Oracle Docs as well as after browsing this space for more time that we can't create automatic partitions at sub-partition level.
I saw some of solutions provided but could not find a solution matching for my case.

Could you please help me out?

My table structure is given below

CREATE TABLE t_partition (
  p_id             NUMBER,
  p_year           NUMBER(4),-- eg 2018
  p_signed_day     DATE,
  p_signed_user    VARCHAR2(10)
)


Here I need the main partition based on p_year to be automatic for each year and then create 12 sub partitions(one for each month) per each year using the p_signed_day field.

I thought through using a sub partition template, but couldn't get it going to take the month information from the Date field while setting sub-partition clause.

How can I achieve this?

Thanks
K R

and Chris said...

Probably the easiest is to:

- Define a virtual column extracting the month from the date
- Subpartition on this
- Create a subpartition template listing out the month values

Then when new top-level partitions are added, you'll get a subpartition/month for them:

create table t (
  ins_date  date,
  ins_year  int as ( extract ( year from ins_date ) ),
  ins_month int as ( extract ( month from ins_date ) )
) partition by range ( ins_year )
  interval ( 1 )
  subpartition by list ( ins_month ) 
  subpartition template (
    subpartition sp_jan values ( 1 ), 
    subpartition sp_feb values ( 2 ), --etc.
    subpartition sp_others values ( default )
  ) (
    partition p2019 values less than ( 2020 )
  );
  
insert into t ( ins_date ) values ( date'2020-01-01' );

select * from t;

INS_DATE                INS_YEAR    INS_MONTH   
01-JAN-2020 00:00:00           2020            1 

select partition_name, subpartition_name
from   user_tab_subpartitions
where  table_name = 'T';

PARTITION_NAME    SUBPARTITION_NAME   
P2019             P2019_SP_JAN         
P2019             P2019_SP_FEB         
P2019             P2019_SP_OTHERS      
SYS_P8460         SYS_SUBP8458         
SYS_P8460         SYS_SUBP8459         
SYS_P8460         SYS_SUBP8457   


Though I have to ask: is p_year derived from p_signed_day? If so, you'd be better off making this a virtual column too (as in my example).

Rating

  (1 rating)

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

Comments

Avoid subpartitioning if possible

Gh, July 31, 2019 - 4:18 am UTC

If the YEAR col is always the year of the DATE col then partition by DATE interval 1 month.
If not then make your virtual column by combining the YEAR and the month of DATE so you could hence all the way partition by test resulting date.
So you avoid subpartitions and this is good for dictionary for indexing for perf and saving space etc..
This is good also for future requirements so you can maybe use subpartition for a new requirements that really really need subpartitioning for business or perf issues or needs.

Chris Saxon
July 31, 2019 - 4:14 pm UTC

I was pondering that too! If the values are related, than basic interval month partitioning seems the better approach to me.

More to Explore

Design

New to good database design? Check out Chris Saxon's full fundamentals class.