I have a scenario in which want to partition an existing Oracle table using interval partitioning. I don't know what is the best approach in the database to do the same.
Table size is around 11 GB. Partitioning needs to be done on Date column with the interval of 1 month.
Recreate the table:
Rename your current table to something like <your-table-name>_OLD
Create a new partitioned table with your original table name.
Insert your table data from the old table to the new table.
Drop the old table.
Precondition: you have the required space available in your database.
And don't forget to recreate all needed constraints etc.
Or use Oracle's online table redefinition mechanism: https://docs.oracle.com/en/database/oracle/oracle-database/12.2/vldbg/evolve-nopartition-table.html#GUID-6054142E-207A-4DF0-A62A-4C1A94DD36C4
If you want only partition the new data and let the old table as one partition you may usi this ismple approach withou reorganisation and required twice space.
0) This is your sample data , ID id the partition column defined up to 10.000
create table my_tab
(id number,
vc1 varchar2(100));
insert into my_tab(id,vc1)
select rownum id, 'xxx'||rownum vc1 from dual connect by level <= 10000;
commit;
1) create empty interval partitione dtable with one partition covering all your data - here ID less then 10.001
create table my_part_tab
(id number,
vc1 varchar2(100))
PARTITION BY RANGE (id)
INTERVAL (1000)
(PARTITION p1 VALUES LESS THAN (10001));
2) Define identical indexes on the partition table as on the original table
3) Exchange your table with the initial partition.
alter table my_part_tab exchange partition P1
with table my_tab
including indexes;
Now your original table is empty and all data are in the partition P1of the partitioned table.
New data (higher keys) would be stored based on the interval partition policy.
Related
The code below would create a new partition if I would insert a date that does not exist in my table. Is it possible to do the same thing in a list partitioned table, where the partition is based on a VARCHAR2 column?
ALTER TABLE MY_TABLE MODIFY
PARTITION BY RANGE(DATE) INTERVAL(NUMTODSINTERVAL(1,'day'))
( partition MY_PARTITION values less than (to_date('2019-06-01', 'yyyy-mm-dd')));
Yes, it is possible starting from the Oracle 12.2.
See the details here.
I got to know as we cannot convert existing non-partitioned table to partitioned table but the below link from the Oracle suggest that with the help of "ONLINE" keyword we can do it.
https://docs.oracle.com/en/database/oracle/oracle-database/12.2/vldbg/evolve-nopartition-table.html#GUID-5FDB7D59-DD05-40E4-8AB4-AF82EA0D0FE5
CREATE TABLE my_tab ( a NUMBER(38,0), b NUMBER(38,0));
ALTER TABLE MY_TAB MODIFY PARTITION BY RANGE (a) INTERVAL (1000) (
PARTITION p1 VALUES LESS THAN (1000)) ONLINE;
But it's not working for me, throwing error as "Invalid Partition Name".
I don't want to use dbms_redefinition.
If you are using Oracle 12c Release 2 you could use single ALTER to convert non-partitioned table to partitioned one :
CREATE TABLE my_tab ( a NUMBER(38,0), b NUMBER(38,0));
ALTER TABLE MY_TAB MODIFY PARTITION BY RANGE (a) INTERVAL (1000) (
PARTITION p1 VALUES LESS THAN (1000)) ONLINE;
On Oracle Database 12c Release 1 (12.1.0.2.0) and without using dbms_redefinition your options may be limited to creating a new partitioned table with the same structure as the original table and copying over the data, creating indexes, constraints etc.
CREATE TABLE my_tab_part -- new partitioned table
PARTITION BY RANGE (a)
INTERVAL ( 1000 )
(PARTITION p1 VALUES LESS THAN (1000))
AS
SELECT * FROM my_tab;
Assume I have a Hive table that includes a TIMESTAMP column that is frequently (almost always) included in the WHERE clauses of a query. It makes sense to partition this table by the TIMESTAMP field; however, to keep to a reasonable cardinality, it makes sense to partition by day (not by the maximum resolution of the TIMESTAMP).
What's the best way to achieve this? Should I create an additional column (DATE) and partition on that? Or is there a way to achieve the partition without creating a duplicate column?
Its not a new column, but its a pseudo-column, You should re-create your table with adding the partitioning specification like this :
create table table_name (
id int,
name string,
timestamp string
)
partitioned by (date string)
Then you load the data creating the partitions dynamically like this
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
FROM table_name_old tno
INSERT OVERWRITE TABLE table_name PARTITION(substring(timestamp,0,10))
SELECT tno.id, tno.name, tno.timestamp;
Now if you select all from your table you will see a new column for the partition, but consider that a Hive partition is just a subdirectory and its not a real column, hence it does not affect the total table size only by some kilobytes.
As partition is also one of the column in hive, every partition has value(assign using static or dynamic partition) and every partition is mapped to directory in HDFS, so it has to be additional column.
You may choose one the below option:
Let's say table DDL:
CREATE TABLE temp( id string) PARTITIONED BY (day int)
If the data is organised day wise then add static partition:
ALTER TABLE xyz
ADD PARTITION (day=00)
location '/2017/02/02';
or
INSERT OVERWRITE TABLE xyz
PARTITION (day=1)
SELECT id FROM temp
WHERE dayOfTheYear(**timestamp**)=1;
Generate day number using dynamic partition:
INSERT INTO TABLE xyz
PARTITION (day)
SELECT id ,
dayOfTheYear(day)
FROM temp;
Hive doesn't have any dayOfTheYear function you create it.
i have searched a lot but i have found nothing about how to
add a range partition to an existing table
alter table myuser.mytable
add PARTITION BY RANGE (mynumber) INTERVAL (1)
( PARTITION p1 VALUES LESS THAN (108))
that gives me ORA:14150 error, SUBPARTITON keyword is missing,
but i dont want to give subpartition
EDIT: On 19c and 12cR2 this can be done using the MODIFY Clause of ALTER TABLE
ALTER TABLE myuser.mytable MODIFY
PARTITION BY RANGE (mynumber) INTERVAL (1)
( PARTITION p1 VALUES LESS THAN (108)
PARTITION p2 VALUES LESS THAN (109))
ONLINE
UPDATE INDEXES
See this from Oracle Docs
PRIOR To 19c or 12cR2:
If your existing Table is Non-Partitioned you will have to:
CREATE a new TABLE with partition definitions. Lets call this table MYTABLE_NEW
INSERT into MYTABLE_NEW all data from MYTABLE
RENAME MYTABLE to MYTABLE_OLD
RENAME MYTABLE_NEW to MYTABLE
DROP MYTABLE_OLD
OR
dbms_redefinition can also be used
See this from AskTom
Also see this other Answer
I have existing table which has 10 years of data (I have taken dump).
I would like to Range partition the existing table on one date key column within the table.
Most of the examples I see are with CREATE TABLE..PARTITION BY RANGE... to add new partitions. But my table is existing table.
I assume I need some ALTER statement.
ALTER TABLE TABLE_NAME
PARTITION BY RANGE(CREATED_DATE)
PARTITION JAN16 VALUES LESS THAN (01-02-2016),
PARTITION FEB16 VALUES LESS THAN (01-03-2016) AND GREATER THAN(31-01-2016),//OR?
PARTITION MAR16 VALUES BETWEEN (01-03-2016) AND (31-03-2016), //OR?
Two questions..
Do I need Alter statement to add partitioning mechanism or need to work with create statement?
What is the proper syntax for keeping each partition having only ONE MONTH data.
If you are using Oracle 12c Release 2 you could use single ALTER to convert non-partitioned table to partitioned one (this is one way trip):
CREATE TABLE my_tab ( a NUMBER(38,0), b NUMBER(38,0));
ALTER TABLE MY_TAB MODIFY PARTITION BY RANGE (a) INTERVAL (1000) (
PARTITION p1 VALUES LESS THAN (1000)) ONLINE;
You could convert indexes too, adding:
update indexes (index_name [local/global]);
db<>fiddle demo
Beacuse your table non-partitioned you have two options:
Export data, drop table, create new patitioned table, import data.
Use split then exchange partition method. https://oracle-base.com/articles/misc/partitioning-an-existing-table-using-exchange-partition
Also, if you want new partition per month read about SET INTERVAL. For example:
CREATE TABLE tst
(col_date DATE)
PARTITION BY RANGE (col_date) INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'))
(PARTITION col_date_min VALUES LESS THAN (TO_DATE('2010-01-01', 'YYYY-MM-DD')));