1. Home
  2. Knowledge Base
  3. Partitioning
  4. Oracle 12c Release 2 Partitioning New Features

Oracle 12c Release 2 Partitioning New Features

A number of enhancements to the Oracle database Partitioning option have been introduced in Oracle Database 12c Release 2.

These include:

  • Automatic List Partitioning
  • Multi-Column List Partitioning
  • Read-only Partitions
  • Filtered Partition maintenance operations
  • Online conversion of non-partitioned to partitioned table
  • Partitioned External Tables

 

Similar to the interval partitioning method which was introduced in Oracle Database 12c Release 1, one of the new partitioning features introduced in Oracle 12c Release 2 is the Automatic List Partitioning feature which makes the partitioned table easier to manage.

The ability to partition a table based on distinct values in a column has been around since quite some time, but what is new in Oracle database 12.2 is that we can initially partition the table based on values that are known and present in the column we would like to partition the table on. As data is loaded into the table, new partitions are automatically created by the database if the loaded partition key value does not correspond to any of the existing partitions.

In Oracle Database 12c Release 2, we can now partition a table based on list of values of multiple columns and not just a single column as in the case of previous versions. This is called Multi-Column List Partitioning.

So if we have a very large table containing sales data for the entire country, we can partition the table based on a state and as well as a city located in the same state.

Another new feature is Read-Only Partitions. So, the entire table is not made read-only, but just some partitions in the table can be made read-only. Maybe we have a requirement to store historical data and older partitions in the table can be made read-only to prevent any DML operations on such ‘old’ data.

As DBA’s, one of the common partition maintenance operations we had to carry out quite regularly was moving partitions – maybe older partitions of the table are moved to a different tablespace hosted on low cost storage because this data is infrequently accessed. Now in Oracle Database 12.2, we can combine partition maintenance operations like MOVE PARTITION, MERGE PARTITION and SPLIT PARTITION with data filtering. So for example, while we are moving data of a particular partition, we can also filter data which will be moved. By specifying a filtering predicate via the INCLUDING ROWS keyword, we can determine what data should be preserved when the partition maintenance operation is carried out and what data can be discarded.

But one of the best new 12.2 features is that we can now convert a non-partitioned table into a partitioned table very easily via the ALTER TABLE command with the MODIFY clause as well as while concurrent DML operations are being performed on the table. So the conversion of the table is an online process and with the UPDATE INDEXES clause we can also convert any indexes on the table into either local or global partitioned indexes as well.

We can also now create a Partitioned External Table. So basically, we are creating a table based on data hosted outside the Oracle database and we partition the table which contains this external data for better optimization of queries which would be really beneficial if we are dealing with very large volumes of these external data sets.

Let us have a look at all these 12c Release 2 Partitioning new features.


First create a test non-partitioned table with an index and insert some data into the table.

 

SQL> CREATE TABLE sales_by_state 
 (sales_state VARCHAR2(3), 
  sales_city VARCHAR2(20),
  sales_quarter NUMBER,
  sales_amount  NUMBER);
 
Table created.

SQL> CREATE INDEX sales_state_ind ON sales_by_state (sales_state);

Index created.


SQL> INSERT INTO sales_by_state 
 VALUES 
 ('WA','PERTH',1,10000);  

1 row created.

SQL> INSERT INTO sales_by_state 
VALUES 
('WA','ALBANY',1,9500);   

1 row created.

SQL> INSERT INTO sales_by_state 
VALUES 
('VIC','MELBOURNE',1,75000);   

1 row created.

SQL> INSERT INTO sales_by_state 
VALUES 
('VIC','GEELONG',1,6500);    

1 row created.

SQL> INSERT INTO sales_by_state 
VALUES 
('NSW','SYDNEY',1,50000);    

1 row created.

SQL> COMMIT;

Commit complete.


SQL> SELECT * FROM sales_by_state;

SAL SALES_CITY		 SALES_QUARTER SALES_AMOUNT
--- -------------------- ------------- ------------
WA  PERTH			     1	      10000
WA  ALBANY			     1	       9500
VIC MELBOURNE		             1	      75000
VIC GEELONG			     1	       6500
NSW SYDNEY			     1	      50000

 

We now convert the non-partitioned table to a multi-column List-Partitioned table online and also create a local partitioned index on the table as well as part of the same operation.
 


SQL> ALTER TABLE system.sales_by_state 
MODIFY 
PARTITION BY LIST (sales_state,sales_city) AUTOMATIC 
(PARTITION p_wa_1 VALUES ('WA','PERTH'),
 PARTITION p_wa_2 values ('WA','ALBANY'),
 PARTITION p_vic_1 values ('VIC','MELBOURNE'),
 PARTITION p_vic_2 values ('VIC','GEELONG'),
 PARTITION p_nsw_1 values ('NSW','SYDNEY'))
 ONLINE 
 UPDATE INDEXES;   

Table altered.

SQL> SELECT PARTITION_NAME FROM USER_TAB_PARTITIONS WHERE TABLE_NAME='SALES_BY_STATE';

PARTITION_NAME
--------------------------------------------------------------------------------
P_NSW_1
P_VIC_1
P_VIC_2
P_WA_1
P_WA_2


SQL> select partition_name from user_IND_PARTITIONS WHERE INDEX_NAME='SALES_STATE_IND';

PARTITION_NAME
--------------------------------------------------------------------------------
P_NSW_1
P_VIC_1
P_VIC_2
P_WA_1
P_WA_2

 

Notice what happens when we insert some new rows into the partitioned table with a state and city value not already present in the table.
 

SQL> INSERT INTO sales_by_state 
     VALUES 
     ('SA','ADELAIDE',1,10500);

1 row created.

SQL> INSERT INTO sales_by_state 
     VALUES
     ('SA','ADELAIDE',2,8000);

1 row created.

SQL> COMMIT; 

Commit complete.

SQL> SELECT PARTITION_NAME FROM USER_TAB_PARTITIONS WHERE TABLE_NAME='SALES_BY_STATE';

PARTITION_NAME
--------------------------------------------------------------------------------
P_NSW_1
P_VIC_1
P_VIC_2
P_WA_1
P_WA_2
SYS_P1323

6 rows selected.

SQL> SELECT COUNT(*) FROM sales_by_state PARTITION(SYS_P1323);

  COUNT(*)
----------
	 2

 
Make one of the partitions in the table read-only.
 

SQL> ALTER TABLE sales_by_state MODIFY PARTITION p_wa_1 READ ONLY;

Table altered.


SQL> INSERT INTO sales_by_state 
     VALUES 
    ('WA','PERTH',2,5000);

INSERT INTO sales_by_state
            *
ERROR at line 1:
ORA-14466: Data in a read-only partition or subpartition cannot be modified.

 
Next, we will create an External partitioned table. We have 4 flat files which contain sales information for particular states and we would like to now create a table which is partitioned by the state name.
 

SQL> !cat salesdata_wa.txt
WA	PERTH		1	10000
WA	ALBANY	1	9500

SQL> !cat salesdata_nsw.txt
NSW	SYDNEY	1	50000

SQL> !cat salesdata_vic.txt 
VIC	MELBOURNE	1	75000
VIC	GEELONG	1	6500

SQL> !cat salesdata.txt
SA	ADELAIDE	1	10500
SA	ADELAIDE	2	8000

 

CREATE TABLE system.sales_by_state 
(sales_state VARCHAR2(3), 
 sales_city VARCHAR2(20),
sales_quarter NUMBER,
 sales_amount  NUMBER)
ORGANIZATION EXTERNAL
(TYPE oracle_loader
DEFAULT DIRECTORY data_pump_dir
ACCESS PARAMETERS 
(RECORDS DELIMITED BY NEWLINE FIELDS TERMINATED BY WHITESPACE)
)
PARTITION BY LIST (sales_state) 
(PARTITION p_wa VALUES ('WA') LOCATION ('salesdata_wa.txt'),
 PARTITION p_vic values ('VIC') LOCATION ('salesdata_vic.txt'),
 PARTITION p_nsw values ('NSW') LOCATION ('salesdata_nsw.txt'),
 PARTITION p_others values (DEFAULT) LOCATION ('salesdata.txt')
)
; 
Table created.

Query the Partitioned External table.
 

SQL> SELECT * FROM sales_by_state;

SAL SALES_CITY		 SALES_QUARTER SALES_AMOUNT
--- -------------------- ------------- ------------
WA  PERTH			     1	      10000
WA  ALBANY			     1	       9500
VIC MELBOURNE			     1	      75000
VIC GEELONG			     1	       6500
NSW SYDNEY			     1	      50000
SA  ADELAIDE			     1	      10500
SA  ADELAIDE			     2	       8000

7 rows selected.

SQL> SELECT * FROM sales_by_state partition (p_wa);

SAL SALES_CITY		 SALES_QUARTER SALES_AMOUNT
--- -------------------- ------------- ------------
WA  PERTH			     1	      10000
WA  ALBANY			     1	       9500

SQL> SELECT * FROM sales_by_state partition (p_nsw);

SAL SALES_CITY		 SALES_QUARTER SALES_AMOUNT
--- -------------------- ------------- ------------
NSW SYDNEY			     1	      50000

 
In this example we will move a partition to another tablespace maybe to archive data and as part of the partition maintenance operation we would like to only preserve rows which satisfy a particular filter which in this case is only rows in the partition belonging to the SALES_QUARTER column with the value 2. All other rows which do not conform to this filter condition will be purged as part of the MOVE PARTITION operation.
 

SQL> SELECT * FROM sales_by_state_part PARTITION (p_wa_);

SAL SALES_CITY		 SALES_QUARTER SALES_AMOUNT
--- -------------------- ------------- ------------
WA  PERTH			     1	      10000
WA  ALBANY			     1	       9500
WA  BROOME			     1	       9700
WA  PERTH			     2	      11000


SQL> ALTER TABLE sales_by_state_part 
  2  MOVE PARTITION p_wa_ TABLESPACE archive_data COMPRESS ONLINE
  3  INCLUDING ROWS WHERE sales_quarter=2;

Table altered.

SQL> SELECT * FROM sales_by_state_part PARTITION (p_wa_);

SAL SALES_CITY		 SALES_QUARTER SALES_AMOUNT
--- -------------------- ------------- ------------
WA  PERTH			     2	      11000

SQL> SELECT TABLESPACE_NAME FROM USER_TAB_PARTITIONS WHERE PARTITION_NAME='P_WA_';

TABLESPACE_NAME
------------------------------
ARCHIVE_DATA
Updated on June 2, 2021

Was this article helpful?

Related Articles

Leave a Comment