Hi,
We have several multi-billion row tables that need to be partitioned. We also want to try some other things to reduce I/O. Specifically:
- Partition by hash
- Purge old records
- Advanced compression on table and indexes
- Cluster by primary key.
We can get everything to work except for compressing the indexes. Can this be done in the ALTER TABLE statement or does it require separate steps? The process will take several hours per table, on a live production system with ongoing transactions. We would like to be able to do it all in one complete online operation per table.
Here is a simple version of what we are trying:
First, create a single segment table:
CREATE TABLE big AS SELECT * FROM sys.dba_objects;
CREATE INDEX big_idx1 ON big (owner, object_name);
EXECUTE DBMS_STATS.gather_table_stats('', 'BIG');
Second, Set attributes for clustering and compression:
ALTER TABLE big ADD CLUSTERING BY LINEAR ORDER (owner);
ALTER TABLE big ROW STORE COMPRESS ADVANCED;
Third, create the new version of the table:
ALTER TABLE big
MODIFY
PARTITION BY HASH (owner) PARTITIONS 8
INCLUDING ROWS WHERE last_ddl_time >= SYSDATE - (4*365)
ONLINE
UPDATE INDEXES (big_idx1 GLOBAL PARTITION BY HASH (owner, object_name) PARTITIONS 8);
The table is partitioned and compressed as expected:
col partition_name format a15
col compression format a12
col compress_for format a12
SELECT partition_name, compression, compress_for
FROM user_tab_partitions
WHERE table_name = 'BIG';
PARTITION_NA COMPRESSION COMPRESS_FOR
------------ ------------ ------------
SYS_P12500 ENABLED ADVANCED
SYS_P12501 ENABLED ADVANCED
SYS_P12502 ENABLED ADVANCED
SYS_P12503 ENABLED ADVANCED
SYS_P12504 ENABLED ADVANCED
SYS_P12505 ENABLED ADVANCED
SYS_P12506 ENABLED ADVANCED
SYS_P12507 ENABLED ADVANCED
8 rows selected.
The index is partitioned but NOT compressed:
col partition_name format a15
col compression format a12
SELECT partition_name, compression
FROM user_ind_partitions
WHERE index_name = 'BIG_IDX1';
PARTITION_NA COMPRESSION
------------ ------------
SYS_P12508 DISABLED
SYS_P12509 DISABLED
SYS_P12510 DISABLED
SYS_P12511 DISABLED
SYS_P12512 DISABLED
SYS_P12513 DISABLED
SYS_P12514 DISABLED
SYS_P12515 DISABLED
8 rows selected.
We have tried everything we could think of to put the COMPRESS ADVANCED HIGH setting into the ALTER TABLE ... UPDATE INDEXES clause but nothing seemed to work. How do we get the indexes to also be compressed and ideally in the same ONLINE ALTER TABLE statement?
Thanks,
Alan
Yeah that doesn't seem right - I'll ask around internally and report back if I get some better info than below.
Addenda: From the docs:
This clause cannot change the uniqueness property of the index or any other index property.
https://docs.oracle.com/en/database/oracle/oracle-database/19/vldbg/evolve-nopartition-table.html
Here's a (hacky) workaround - we'll create the compressed index in advance to preserve the compression. Afterwards, drop the uncompressed one
SQL> create table big as select * from sys.dba_objects;
Table created.
SQL> create index big_idx1 on big (owner, object_name);
Index created.
SQL> execute dbms_stats.gather_table_stats('', 'BIG');
PL/SQL procedure successfully completed.
SQL> alter table big add clustering by linear order (owner);
Table altered.
SQL> alter table big row store compress advanced;
Table altered.
SQL> create index tmp_ix on big (owner, object_name, null) compress 2;
Index created.
SQL> alter table big
2 modify
3 partition by hash (owner) partitions 8
4 including rows where last_ddl_time >= sysdate - (4*365)
5 online
6 update indexes (
7 big_idx1 global partition by hash (owner, object_name) partitions 8 ,
8 tmp_ix global partition by hash (owner, object_name) partitions 8
9 );
Table altered.
SQL>
SQL> col partition_name format a15
SQL> col compression format a12
SQL> col compress_for format a12
SQL>
SQL> select partition_name, compression, compress_for
2 from user_tab_partitions
3 where table_name = 'BIG';
PARTITION_NAME COMPRESSION COMPRESS_FOR
--------------- ------------ ------------
SYS_P13826 ENABLED ADVANCED
SYS_P13827 ENABLED ADVANCED
SYS_P13828 ENABLED ADVANCED
SYS_P13829 ENABLED ADVANCED
SYS_P13830 ENABLED ADVANCED
SYS_P13831 ENABLED ADVANCED
SYS_P13832 ENABLED ADVANCED
SYS_P13833 ENABLED ADVANCED
8 rows selected.
SQL>
SQL> col partition_name format a15
SQL> col compression format a12
SQL>
SQL> select partition_name, compression
2 from user_ind_partitions
3 where index_name in ('BIG_IDX1','TMP_IX');
PARTITION_NAME COMPRESSION
--------------- ------------
SYS_P13834 DISABLED
SYS_P13835 DISABLED
SYS_P13836 DISABLED
SYS_P13837 DISABLED
SYS_P13838 DISABLED
SYS_P13839 DISABLED
SYS_P13840 DISABLED
SYS_P13841 DISABLED
SYS_P13842 ENABLED
SYS_P13843 ENABLED
SYS_P13844 ENABLED
SYS_P13845 ENABLED
SYS_P13846 ENABLED
SYS_P13847 ENABLED
SYS_P13848 ENABLED
SYS_P13849 ENABLED
16 rows selected.
SQL> drop index big_ix;
Index dropped.
SQL>
SQL>
SQL>
Addenda: But also see Rajesh's option in the comments for another nifty workaround