8i | 9i | 10g | 11g | 12c | 13c | 18c | 19c | 21c | 23c | Misc | PL/SQL | SQL | RAC | WebLogic | Linux

Home » Articles » 23c » Here

Hybrid Partitioned Table Enhancements in Oracle Database 23c

Hybrid partitioned tables were introduced in Oracle 19c, allowing us to create partitioned tables with a mix of internal and external partitions. In 19c it was not possible to combine this with interval or auto-list partitioning, but that has changed in Oracle database 23c. This article demonstrates hybrid partitioned tables with interval and auto-list partitioning in Oracle Database 23c.

Hybrid Partitioned Tables

Related articles.

Setup

Connect to a privileged user and create a new test user called TESTUSER1.

conn sys/SysPassword1@//localhost:1521/freepdb1 as sysdba

drop user if exists testuser1 cascade;

create user testuser1 identified by testuser1 quota unlimited on users;
grant db_developer_role to testuser1;

Create a directory object, making sure TESTUSER1 has READ, WRITE and EXECUTE permissions on them.

create or replace directory tmp_dir1 as '/tmp/';
grant read, write, execute on directory tmp_dir1 to testuser1;

All other actions will be performed from TESTUSER1.

conn testuser1/testuser1@//localhost:1521/freepdb1

Hybrid Partitioned Table With Interval Partitioning

Generate some flat files with dummy data for use with external table partitions.

set markup csv on quote on
set trimspool on linesize 1000 feedback off pagesize 0

spool /tmp/2022-1.txt
select '2022-01-01',
       object_id,
       owner,
       object_name
from   all_objects
where  object_id <= 3999
and    rownum <= 1000;
spool off

spool /tmp/2022-2.txt
select '2022-01-01',
       object_id,
       owner,
       object_name
from   all_objects
where  object_id between 4000 and 5999
and    rownum <= 1000;
spool off

set markup csv off
set trimspool on linesize 1000 feedback on pagesize 14

The following example creates a hybrid partitioned table. It uses interval partitioning, with a single external partition for 2022 data, and a single internal partitions for 2023 data respectively.

drop table if exists test_ol_hybrid_part_tab purge;

create table test_ol_hybrid_part_tab (
  created_date  date          not null,
  object_id     number        not null,
  owner         varchar2(128) not null,
  object_name   varchar2(128) not null
)
  external partition attributes (
    type oracle_loader 
    default directory tmp_dir1
    access parameters (
      fields csv with embedded terminated by ',' optionally enclosed by '"'
      missing field values are null
      (created_date date "YYYY-MM-DD", object_id, owner, object_name)
    ) 
    reject limit unlimited
  ) 
  partition by range (created_date) 
  interval (numtoyminterval(1,'YEAR')) (
    partition part_2022 values less than (to_date('2023-01-01','YYYY-MM-DD')) external
      location ('2022-1.txt', '2022-2.txt'),
    partition part_2023 values less than (to_date('2024-01-01','YYYY-MM-DD'))
  );

The EXTERNAL PARTITION ATTRIBUTES clause defines the table-level external table parameters. For external partitions, the EXTERNAL clause is used to define partition-level attributes, such as file locations and non-default directory objects.

The HYBRID column in the CDB|DBA|ALL|USER}_TABLES views show this is a hybrid table.

column table_name format a30
column hybrid format a6

select table_name, hybrid from user_tables;

TABLE_NAME                     HYBRID
------------------------------ ------
TEST_OL_HYBRID_PART_TAB        YES

1 row selected.

SQL>

We only have data in the external partitions at the moment.

column created_date format a12

select to_char(created_date,'YYYY') as created_date, count(*) as amount
from   test_ol_hybrid_part_tab
group by created_date
order by created_date;

CREATED_DATE     AMOUNT
------------ ----------
2022               2000

1 row selected.

SQL>

We can perform DML on the internal partition as normal.

insert into test_ol_hybrid_part_tab
select to_date('2023-01-01','YYYY-MM-DD'),
       object_id,
       owner,
       object_name
from   all_objects
where  rownum <= 2000;
commit;


column created_date format a12

select to_char(created_date,'YYYY') as created_date, count(*) as amount
from   test_ol_hybrid_part_tab
group by created_date
order by created_date;

CREATED_DATE     AMOUNT
------------ ----------
2022               2000
2023               2000

2 rows selected.

SQL>

All this behaviour is typical for a hybrid list partitioned table. Because this is an interval hybrid partitioned table, we can also insert records for new years, which create new partitions. First we check the current partitions for the table.

column partition_name format a30

select partition_name
from   user_tab_partitions
where  table_name = 'TEST_OL_HYBRID_PART_TAB'
order by 1;

PARTITION_NAME
------------------------------
PART_2022
PART_2023

2 rows selected.

SQL>

Now we insert some data for two new years.

insert into test_ol_hybrid_part_tab
select to_date('2024-01-01','YYYY-MM-DD'),
       object_id,
       owner,
       object_name
from   all_objects
where  rownum <= 2000;
commit;

insert into test_ol_hybrid_part_tab
select to_date('2025-01-01','YYYY-MM-DD'),
       object_id,
       owner,
       object_name
from   all_objects
where  rownum <= 2000;
commit;

We can see two new partitions have been created for the new years.

column partition_name format a30

select partition_name
from   user_tab_partitions
where  table_name = 'TEST_OL_HYBRID_PART_TAB'
order by 1;

PARTITION_NAME
------------------------------
PART_2022
PART_2023
SYS_P467
SYS_P468

4 rows selected.

SQL>

And of course we can see the data is present when we query the table.

column created_date format a12

select to_char(created_date,'YYYY') as created_date, count(*) as amount
from   test_ol_hybrid_part_tab
group by created_date
order by created_date;

CREATED_DATE     AMOUNT
------------ ----------
2022               2000
2023               2000
2024               2000
2025               2000

4 rows selected.

SQL>

Hybrid Partitioned Table With Auto-List Partitioning

Generate some flat files with dummy data for use with external table partitions.

set markup csv on quote on
set trimspool on linesize 1000 feedback off pagesize 0

spool /tmp/gbr1.txt
select 'GBR',
       object_id,
       owner,
       object_name
from   all_objects
where  object_id <= 3999
and    rownum <= 1000;
spool off

spool /tmp/gbr2.txt
select 'GBR',
       object_id,
       owner,
       object_name
from   all_objects
where  object_id between 4000 and 5999
and    rownum <= 1000;
spool off

spool /tmp/ire1.txt
select 'IRE',
       object_id,
       owner,
       object_name
from   all_objects
where  object_id <= 3999
and    rownum <= 1000;
spool off

spool /tmp/ire2.txt
select 'IRE',
       object_id,
       owner,
       object_name
from   all_objects
where  object_id between 4000 and 5999
and    rownum <= 1000;
spool off

set markup csv off
set trimspool on linesize 1000 feedback on pagesize 14

The following example creates a hybrid partitioned table. It uses auto-list partitioning, with a single internal partition for USA data, and two external partitions for GBR and IRE data respectively.

drop table if exists test_ol_hybrid_part_tab purge;

create table test_ol_hybrid_part_tab (
  country_code  varchar2(3)   not null,
  object_id     number        not null,
  owner         varchar2(128) not null,
  object_name   varchar2(128) not null
)
  external partition attributes (
    type oracle_loader 
    default directory tmp_dir1
    access parameters (
      fields csv with embedded terminated by ',' optionally enclosed by '"'
      missing field values are null
      (country_code, object_id, owner, object_name)
    ) 
    reject limit unlimited
  ) 
  partition by list (country_code) automatic (
    partition usa values ('USA'),
    partition gbr values ('GBR') external
      location ('gbr1.txt', 'gbr2.txt'),
    partition ire values ('IRE') external
      location ('ire1.txt', 'ire2.txt')
  );

The EXTERNAL PARTITION ATTRIBUTES clause defines the table-level external table parameters. For external partitions, the EXTERNAL clause is used to define partition-level attributes, such as file locations and non-default directory objects.

The HYBRID column in the CDB|DBA|ALL|USER}_TABLES views show this is a hybrid table.

column table_name format a30
column hybrid format a6

select table_name, hybrid from user_tables;

TABLE_NAME                     HYBRID
------------------------------ ------
TEST_OL_HYBRID_PART_TAB        YES

1 row selected.

SQL>

We only have data in the external partitions at the moment.

column country_code format a12

select country_code, count(*) as amount
from   test_ol_hybrid_part_tab
group by country_code
order by country_code;

COUNTRY_CODE     AMOUNT
------------ ----------
GBR                2000
IRE                2000

2 rows selected.

SQL>

We can perform DML on the internal partition as normal.

insert into test_ol_hybrid_part_tab
select 'USA',
       object_id,
       owner,
       object_name
from   all_objects
where  rownum <= 2000;
commit;


column country_code format a12

select country_code, count(*) as amount
from   test_ol_hybrid_part_tab
group by country_code
order by country_code;

COUNTRY_CODE     AMOUNT
------------ ----------
GBR                2000
IRE                2000
USA                2000

3 rows selected.

SQL>

All this behaviour is typical for a hybrid list partitioned table. Because this is an auto-list hybrid partitioned table, we can also insert records for new countries, which create new partitions. First we check the current partitions for the table.

column partition_name format a30

select partition_name
from   user_tab_partitions
where  table_name = 'TEST_OL_HYBRID_PART_TAB'
order by 1;

PARTITION_NAME
------------------------------
GBR
IRE
USA

3 rows selected.

SQL>

Now we insert some data for two new countries.

insert into test_ol_hybrid_part_tab
select 'FRA',
       object_id,
       owner,
       object_name
from   all_objects
where  rownum <= 2000;
commit;

insert into test_ol_hybrid_part_tab
select 'DEU',
       object_id,
       owner,
       object_name
from   all_objects
where  rownum <= 2000;
commit;

We can see two new partitions have been created for the new countries.

column partition_name format a30

select partition_name
from   user_tab_partitions
where  table_name = 'TEST_OL_HYBRID_PART_TAB'
order by 1;

PARTITION_NAME
------------------------------
GBR
IRE
SYS_P462
SYS_P463
USA

5 rows selected.

SQL>

And of course we can see the data is present when we query the table.

column country_code format a12

select country_code, count(*) as amount
from   test_ol_hybrid_part_tab
group by country_code
order by country_code;

COUNTRY_CODE     AMOUNT
------------ ----------
DEU                2000
FRA                2000
GBR                2000
IRE                2000
USA                2000

5 rows selected.

SQL>

For more information see:

Hope this helps. Regards Tim...

Back to the Top.