* You can't migrate to Oracle 11g on the fly. You're stuck in 10g
* You also need to drop the oldest partition, because you have lack of storage issues
Then if you are in this situation we have the solution for you. It's bullet-proof tested and proven at production sites.
Every night you need to add another partition and remove the oldest. Pure moving window stuff. The format of the partition name is: PXXXX_YYYY_MM_DD, where XXXX is a sequential number that increments every day. This is daily partitioning and should only have a job running this code everynight:
declare
x varchar2(90);
s varchar2(900);
begin
-- Fetchs the name of the oldest partition
select partition_name
into x
from sys.dba_tab_partitions
where partition_position = 1
and table_name = 'MYTABLE'
and table_owner = 'MYOWNER';
-- Builds the name-string
s := 'ALTER TABLE MYOWNER.MYTABLE DROP PARTITION '||x||' UPDATE INDEXES';
-- Uses a customized report and sends it by email
-- so you can see the partitions state before and after
MYOWNER.my_pkg.sends_email('REPORT6');
-- Drops the Partition
execute immediate s;
-- And now adds another
MYOWNER.add_partition;
MYOWNER.my_pkg.sends_email('REPORT6');
--dbms_output.put_line(s);
end;
The procedure "add_partition" is another piece of automatic code that you must create prior to the previous PL/SQL block:
CREATE OR REPLACE procedure MYOWNER.add_partition
is
next_part varchar2(40);
less_than_char varchar2(20);
comando_add varchar2(1000);
BEGIN
-- Generates the name of the partition
select 'P'||to_char(to_number(substr(partition_name,2,
instr(partition_name,'_',1)-2))+1)||'_'||
to_char(to_date(substr(partition_name,
instr(partition_name,'_',1)+1),'yyyy_mm_dd')+1,'yyyy_mm_dd'),
replace(to_char(to_date(substr(partition_name,
instr(partition_name,'_',1)+1),'yyyy_mm_dd')+2,'yyyy_mm_dd'),'_','-')
into next_part,less_than_char
from dba_tab_partitions
where table_owner = 'MYOWNER'
and table_name = 'MYTABLE'
and partition_position = (select max(partition_position)
from dba_tab_partitions where table_owner = 'MYOWNER'
and table_name = 'MYTABLE');
-- Builds the statement string
comando_add := 'ALTER TABLE MYOWNER.MYTABLE ADD PARTITION '||next_part;
comando_add := comando_add||' VALUES LESS THAN (to_date('||chr(39)||less_than_char;
comando_add := comando_add||chr(39)||','||chr(39)||
'yyyy-mm-dd'||chr(39)||')) TABLESPACE DATA_PARTITIONED';
-- Executes the statement
execute immediate(comando_add);
--dbms_output.put_line(comando_add);
end;
/
You will have permission issues that you can resolve reading this.
If you need any further help applying this, please let me know.
LMC.
[...] Luis Moreno Campos-Automatic Partition Management for Oracle 10g [...]
ReplyDeleteHi..
ReplyDeleteNice one!!! Will definitely try it out..What changes need to be done, if want to drop and add monthly partitions.
Regards,
Anand
Thanks Anand.
ReplyDeleteThese scripts assume that the daily partitions of the table have the following format:
PXXXX_YYYY_MM_DD
where XXXX is a number, and the rest is a date mask. So if you want to adapt this to monthly I think that you just have to decide first on a format for your partition names. Assuming you don't want to adapt too much my scripts, just wipe off the "_DD" part of format, and replace in the script "YYYY_MM_DD" with" YYYY_MM" and everything should work fine.
Cheers,
LMC.
Hi, this looked to be exactly what I needed (much appreciate that it's visible on the web and thanks for sharing). However, on trying the create part, my SQLDevelper tool says it's ignoring the statement:
ReplyDeleteselect 'P'||to_char(to_number(substr(partition_name,2,instr(partition_name,'_',1)-2))+1)||'_'||to_char(to_date(substr(partition_name,instr(partition_name,'_',1)+1),
then goes onto say my table does not exist at this point:
and partition_position = (select max(partition_position) from dba_tab_partitions where table_owner = 'table_owner' AND table_name = 'table_name');
(I tried the above section as a simple select statement and it returns as expected).
Admittedly, my SQL skills are a bit rusty.
Any suggestions would be greatly appreciated.
Cheers
Lex
I would check the quotes first, because it seems to be two of them in the statement. Wordpress posts are hard to format and probably the fault is mine. Anyway, reduce everything to the same basic simple quote => '
ReplyDeleteThanks for reading and commenting.
LMC.
i need similar type solution but for number of tables say 10 or 50 .how your script can be used?
ReplyDeleteEasy.
ReplyDeleteTransform the Anonymous block (the one that starts with DECLARE) into a procedure.
Where you read DECLARE substitute with:
create or replace procedure drop_and_create_partition (tabname varchar2)
Substitute the following block:
and table_name = 'MYTABLE'
and table_owner = 'MYOWNER';
-- Builds the name-string
s := 'ALTER TABLE MYOWNER.MYTABLE DROP PARTITION '||x||' UPDATE INDEXES';
By this one:
and table_name = tabname
and table_owner = 'MYOWNER';
-- Builds the name-string
s := 'ALTER TABLE MYOWNER.'||tabname||' DROP PARTITION '||x||' UPDATE INDEXES';
Then in the other procedure make the following adjustments:
Where you read:
CREATE OR REPLACE procedure MYOWNER.add_partition
You should code it like:
CREATE OR REPLACE procedure MYOWNER.add_partition (tabname varchar2)
And where you read:
and table_name = 'MYTABLE'); (actually there are two lines like this)
You should code it like:
and table_name = tabname);
And where you read:
comando_add :='ALTER TABLE MYOWNER.MYTABLE ADD PARTITION '||next_part;
You should code it like:
comando_add :='ALTER TABLE MYOWNER.'||tabname||' ADD PARTITION '||next_part;
And in the end just invoke:
SQL> exec drop_and_create_partition('Table1');
SQL> exec drop_and_create_partition('Table2');
SQL> exec drop_and_create_partition('Table3');
(...)
SQL> exec drop_and_create_partition('Table50');
Hope it helped.
LMC.
Hi,
ReplyDeleteIts really gud one.thanks for your inputs.
right now my scenraio is we have 100 tables which are monthly partioned,and management wanted to drop future partitions(say from april to dec partitons) in all the 100 tables and wanted to convert them as daily partitons.how do i need to go ahead.as am newbie to partitions.
your inputs are more valuable to me.
thanks
You can partition by Month and then subpartition by day.
ReplyDeleteIf you want to read more about these features, please click "Go Tropical" in this page on the right top side and choose your database version.
There you'll have lots of info to chew on for the next century ;-)
Cheers,
LMC:
thanks for your reply.
ReplyDeleteall the tables were already monthly partioned.
am not good enough in pl/sql so asked for converting into dauly partitions at one stretch.
thnaks in advance.
Without giving it a second thought I would say subpartitioned the table would be the closest to a "one-strech" operation you can get.
ReplyDeleteIf someone out there has some other pre-cooked stuff it's time to show the recipe.
You're welcomed manjula.
LMC.
hi, thanks for the code but when i execute the code...
ReplyDeletedeclare
x varchar2(90);
s varchar2(900);
Begin
-- Fetchs the name of the oldest partition
select partition_name
into x
from user_tab_partitions
where partition_position = 1
and table_name = 'EMP3'
-- and table_owner = 'SCOTT';
-- Builds the name-string
s:='ALTER TABLE EMP3 DROP PARTITION ' || x ||' UPDATE INDEXES;
-- Drops the Partition
execute immediate s;
end;
/
ERROR at line 13:
ORA-06550: line 13, column 2:
PL/SQL: ORA-00933: SQL command not properly ended
ORA-06550: line 6, column 2:
PL/SQL: SQL Statement ignored
i have ignored the
The is a character missing!
ReplyDeleteWhere you have: s:=’ALTER TABLE EMP3 DROP PARTITION ‘ || x ||’ UPDATE INDEXES;
You should have: s:=’ALTER TABLE EMP3 DROP PARTITION ‘ || x ||’ UPDATE INDEXES';
Hope it runs now.
LMC
Hi,
ReplyDeleteHow to drop interval partitions by day
Very helpful!
ReplyDeleteCan you post the code for you partition report by any chance?
You would have to merge them first into the day unit, and then wipe them off or exchange partition with an empty table.
ReplyDeleteLMC
Sorry but I can't because it stayed under the customer realm.
ReplyDeleteLMC
You are an oracle angel, Of course, this code can be used by trigger or scheduler. I just need to add a parttion, any cooked code for trigger?
ReplyDeleteI'm afraid not Bill. Nothing in the hoven either :-)
ReplyDeleteTo implement this as a trigger, it's just a dangerous way of doing it, but if well done, might be the cherry on top of the cake.
If you sort it out please share.
Cheers,
LMC
My case is partition by numeric range, and next number is created by a sequencer. I'm think when sequencer is called then trigger the add_partition, I need to figure out the trigger, seq.nextval -->add_partiotion, any idea?
ReplyDeleteOK, I create a dummy table once I have the nextval, I insert into the table which has a trigger after insertion, any better idea?
ReplyDeleteJust tried running this. And somehow it is complaining for table not existing. Not sure where it is reading it from.
ReplyDeleteCREATE OR REPLACE procedure PACKMAN.add_partition
2 is
next_part varchar2(40);
4 less_than_char varchar2(20);
5 comando_add varchar2(1000);
6 BEGIN
7 select 'P'||to_char(to_number(substr(partition_name,2,instr(partition_name,'_',1)-2))+1)|| '_' ||to_char(to_date(substr(partition_name,instr(partition_name,'_',1)+1),'yyyy_mm_dd')+1,'yyyy_mm_dd'),replace(to_char(to_date(substr(partition_name,instr(partition_name,'_',1)+1),'yyyy_mm_dd')+2,'yyyy_mm_dd'),'_','-') from dba_tab_partitions where table_name ='DUMMY_xxx_EVxx_TRACKER_N';
8 end;
9 /
Warning: Procedure created with compilation errors.
DBANEW>show error
Errors for PROCEDURE PACKMAN.ADD_PARTITION:
LINE/COL
--------------------------------------------------------------------------------
ERROR
--------------------------------------------------------------------------------
7/1
PL/SQL: SQL Statement ignored
7/318
PL/SQL: ORA-00942: table or view does not exist
You have to have permissions to the underlying tables that support the "dba_tab_partitions" view.
ReplyDeleteIf you have problems getting those and the schema where you're creating this procedure is the owner of the tables then try using "user_tab_partitions" instead.
LMC
hey many thanks for the wonderfull post. I have a requirement of creating a backup table on an existing table which is critical for the business atleast once a week so as to preserve a weeks data. This table is around 500MB with approx 1 million rows.
ReplyDeleteHow do you think i must go about it. Need your suggestions.
Chris
What is the Oracle Database version? If it's 11g you can use interval partitioning to have your last week in a specific partition/tablespace, backup that tablespace with rman and then split the partition and move on to the next week. If it's below 11g (10g or 9/8i) then you can export part of that table every week. Though the best would be to have a backup strategy for the whole database that could include this specific table backup requirements.
ReplyDeleteHi Luis, Please help me to create partition daily in 10g? I'll use this:
ReplyDeletePARTITION P_20602 VALUES LESS THAN (20602). What changes in your script that need to be done?
Thank you very much!
Have you ever thought about including a little bit more than just your articles?
ReplyDeleteI mean, what you say is valuable and everything. However imagine if you added some great images or video
clips to give your posts more, "pop"! Your content is excellent but with images and videos, this blog could definitely be one of the most beneficial in
its niche. Wonderful blog!
I would like to implement this dynamic Partitioning in Oracle 10g by addiing / spliting a default partition and am looking for more information how to handle indexes after this change, in the cases of default partition space around 35 GB. Please guide.
ReplyDeleteRan into the same issue, did some digging, apparently there's a product that supports automatic partitioning maintenance from version 9i, including archiving or dropping old partitions, statistics copy between partitions, all date resolutions (hourly, daily, monthly, yearly, w/e) and more stuff, looks cool - http://www.xyrosoft.com.
ReplyDeletegonna check it out and post back.
thanks for the blog, great reading.
update
ReplyDeleteInstalled the product I mentioned in the post above on one of our test environment, agentless (automated processes seems to run on database jobs). the GUI is pretty nice, took me 10 minutes to configure automation of partition cycle on 23 tables. still testing the partition archiving process, but so far looks pretty good.
hope it helps the rest of you... goodluck!
Thanks for the link.
ReplyDeleteI was looking for something like this.
will test it on my env.
Can we call the procedure ( which will add partitions) in trigger?
ReplyDeleteI want to create dynamic partition based on month. So
ReplyDeleteI created a procedure to add partition as you mentioned in example and i'm calling procedure to create partition like below
create or replace
trigger check_date
before insert or update of p_date on mytable
for each row
declare
l_date VARCHAR2(10) := NULL;
begin
select to_char(to_date(substr(max(partition_name),instr(max(partition_name),'_',1)+5),'yyyy_mm'),'yyyy_mm') INTO l_date
from
dba_tab_partitions where table_owner = 'WAREHOUSE'
and table_name = 'MYTABLE'
and partition_position =
(select min(partition_position)
from dba_tab_partitions
where table_owner = 'WAREHOUSE' and table_name ='MYTABLE');
IF to_date(:new.p_date,'dd-mm-yyyy') > to_date(l_date,'yyyy-mm') THEN
add_partition;
END IF;
end;
When i'm inserting date value which is more than the partition range , it is not creating new partition and it is throwing an error :
One error saving changes to table "WAREHOUSE"."MYTABLE":
Row 3: ORA-14400: inserted partition key does not map to any partition
Please help!
Hello Luis ,
ReplyDeleteI am new to Oracle PL/SQL ...
I need to parition table following a certain schema based on number of days such as 10 ...
I need to start inserting data in new parition on every 12th day and simultanelously delete the data of last 11 days stored in same parition1, how can i achieve it ?
Please help .... its very urgent
ReplyDeleteHi,
ReplyDeleteI have the requirement to automate the process of partition creation for next year. create daily partitions and convert them to half monthly and some tables to monthly partitions. Any suggestions would be of gfreat help i am new to partioning
Hi Luis,
ReplyDeleteI would like to drop partitions Older than 6 Months and Check the Partition availability for next 3 Months . Partitions are based on range and using date