Tout sur la compression HCC Hybrid Columnar Compression

Travaillant sur un document d’étude pour l’implémentation de cette compression, je me suis dit que je pouvais partager plus amplement les éléments trouvés sur la mise en place de ce type de compression.
Voici ces informations qui permettent de bien cerner le sujet.
 
 
 

 
 

Présentation de la fonctionnalité « Hybrid Columnar Compression »   – HCC

Traditionnellement, les données pour une base de données relationnelle sont organisées au format ligne dans un bloc. Les informations de chaque colonne sont mises à la suite les unes des autres et remplissent les blocs. On se retrouve ainsi avec une juxtaposition de données de types différents (nombre, date, chaines de caractères) qu’il est alors difficile de compresser efficacement. Une alternative est de stocker les données sous un format différent, regroupées et organisées par colonne.
Ranger les données des colonnes ensemble, regroupant ainsi des informations de mêmes caractéristiques, permet d’obtenir des taux de compression supérieurs, mais va amener des problèmes de performances quand l’application va traiter plusieurs colonnes, faire des mises à jour sur les lignes, ou simplement travailler sur peu de lignes.
Pour limiter cet impact, la fonctionnalité « hybrid columnar compression » ne va pas travailler sur l’ensemble des lignes de la table, mais faire un regroupement des données en colonne pour un jeu de lignes, d’où le terme « hybride ». Au chargement des données, les valeurs des colonnes pour un ensemble de lignes sont regroupées, compressées et stockées dans unité logique de compression nommée « Compression Unit » (CU). On se retrouve ainsi avec, dans le bloc, des sections complètes correspondant aux valeurs d’une même colonne, compressées, comme on peut le voir dans le schéma ci-dessous :
 

 
Pour une efficacité maximale de la compression, les données doivent être chargées dans la table via les techniques de chargement direct :
– Ordre insert avec le hint « APPEND »
– Opération de chargement parallèle
– SLQ*Loader en mode direct
– Ordre de type « CREATE TABLE AS SELECT »
Pendant les requêtes, les blocs sont gérés tels quels et sont transférés vers le buffer cache compressés. C’est seulement à ce niveau que le processus serveur associé réalise la décompression du bloc, ce qui limite les volumes transférés entre le stockage et la mémoire; ce qui est encore plus pertinent dans le cadre des « smart scan » sur les machines Exadata et participe à la performance globale.
Les données restent disponibles pour toutes les opérations DML comme UPDATE ou DELETE, mais, en cas modifications fréquentes ce n’est pas le mode de compression idéale et on lui préférera le mode « Advanced Row Compression », dont l’usage est soumis à la licence de l’option ACO (Advanced Compression Option).
Pour une table partitionnée, certaines partitions peuvent être compressées avec la compression HCC alors que d’autres partitions ne sont pas du tout compressées.

Critères d’éligibilité

1) Architectures valides

Les environnements Oracle supportés pour la compression HCC  sont :
• Appliance EXADATA
• Appliance SuperCluster
• Appliance de stockage ZFS
• Appliance de sauvegarde ZRLA
• Oracle ALL Flash FS Storage System (FS1)

2)  Tables inéligibles

Tables à éliminer de l’ensemble à traiter car incompatibles avec la fonctionnalité  :
a) Ensemble des tables livrées par l’éditeur, appartenant aux schémas fournis à la création de la base ou à la mise en place de fonctionnalités spécifiques (« Outline », « Workspace Manager », « XDB » etc…).
Sont donc à éliminer toutes les tables dont le propriétaire est dans l’ensemble suivant (liste non complète).
On peut ainsi définir une variable nommée « NOTUSERS » , qui prend en compte l’ensemble de ces schémas et que l’on utilisera dans les requêtes SQL pour alléger l’écriture et ajouter facilement un élément en cas d’oubli.

DEFINE NOTUSERS="('SYS', 'SYSTEM' ,'OUTLN','DIP','ORACLE_OCM', 'DBSNMP','APPQSSYS','WMSYS','EXFSYS', 'SYSMAN' ,'XDB' )"; 

b) Les données de type : RAW , LONG RAW , LONG , BLOB et CBLOB ne sont pas compatibles avec la compression HCC. On retrouve la liste par la requête :

SELECT OWNER, TABLE_NAME FROM DBA_TAB_COLUMNS WHERE DATA_TYPE IN ('RAW', 'LONG', 'LONG RAW', 'BLOB' , 'CLOB')
AND OWNER NOT IN &NOTUSERS
/

c)  Tables de construction IOT :

SELECT OWNER, TABLE_NAME FROM DBA_TABLES WHERE IOT_TYPE='IOT' AND OWNER NOT IN &NOTUSERS

d)  Tables temporaires :

SELECT OWNER, TABLE_NAME FROM DBA_TABLES WHERE TEMPORARY='Y' AND OWNER NOT IN &NOTUSERS
/ 

e) Tables de type Clustered Table :

SELECT OWNER, TABLE_NAME FROM DBA_TABLES WHERE CLUSTER_NAME IS NOT NULL AND OWNER NOT IN &NOTUSERS
/  

f) Table avec propriété « ROWDEPENDENCIES » enabled sur la table :

SELECT OWNER, TABLE_NAME FROM DBA_TABLES WHERE DEPENDENCIES='ENABLED' AND OWNER NOT IN &NOTUSERS
/

Liste complète des tables inéligibles, avec raison de l’inéligibilité  :

SELECT OWNER, TABLE_NAME , ' --> DATATYPE NON supporté' "RAISON" from DBA_TAB_COLUMNS WHERE DATA_TYPE IN ('RAW','LONG','LONG RAW', 'BLOB','CLOB')
AND OWNER NOT IN &NOTUSERS
UNION
SELECT OWNER, TABLE_NAME , ' --> IOT NON supporté' FROM DBA_TABLES WHERE IOT_TYPE='IOT' AND OWNER NOT IN &NOTUSERS
UNION
SELECT OWNER, TABLE_NAME , ' --> TABLE temporaire NON supportée' FROM DBA_TABLES WHERE TEMPORARY='Y' AND OWNER NOT IN &NOTUSERS
UNION
SELECT OWNER, TABLE_NAME , ' --> CLUSTER de TABLE NON supporté' FROM DBA_TABLES WHERE CLUSTER_NAME IS NOT NULL AND OWNER NOT IN &NOTUSERS
UNION
SELECT OWNER, TABLE_NAME , ' --> ROWDEPENDENCIES NON supporté' FROM DBA_TABLES WHERE DEPENDENCIES='ENABLED' AND OWNER NOT IN &NOTUSERS
ORDER BY OWNER, TABLE_NAME
/ 

 

Tables cibles naturelles

Les tables cibles naturelles sont les tables contenant des données historiques, idéalement partitionnées ou sous-partitionnées sur un critère temporel.
• Déterminer et valider qu’il y a bien des licences couvrant l’usage du partitionnement.
• Obtenir la liste des tables partitionnées et sous-partitionnées :

SELECT OWNER, TABLE_NAME FROM DBA_TABLES WHERE PARTITIONED='YES' AND OWNER NOT IN &NOTUSERS ;

Autre possibilité :

SELECT TABLE_OWNER, TABLE_NAME FROM DBA_TAB_PARTITIONS WHERE TABLE_OWNER NOT IN &NOTUSERS ;

• Croiser les informations avec les clauses d’inéligibilité
• Déterminer si le critère de partitionnement est un élément temporel, une des manières est de regarder la colonne « HIGH_VALUE » de DBA_TAB_PARTITIONS et de DBA_TAB_SUBPARTITIONS pour voir si elle contient une information de type DATE.
Attention, la colonne « HIGH_VALUE » étant de type LONG, il faut passer par un curseur PL/SQL pour réaliser la conversion en chaine de caractères et pouvoir faire la comparaison :

SET SERVEROUTPUT ON
BEGIN
FOR r IN (SELECT TABLE_OWNER, TABLE_NAME, HIGH_VALUE FROM DBA_TAB_PARTITIONS WHERE TABLE_OWNER NOT IN &NOTUSERS) LOOP
IF SUBSTR(r.HIGH_VALUE, 1, 7) = 'TO_DATE' THEN
DBMS_OUTPUT.PUT_LINE(
'La Table: ' ||r.table_owner||'.'|| r.TABLE_NAME || ' est éligible'
);
END IF;
END LOOP;
END;
/
BEGIN
FOR r IN (SELECT * FROM DBA_TAB_SUBPARTITIONS WHERE TABLE_OWNER NOT IN &NOTUSERS ) LOOP
IF SUBSTR(r.HIGH_VALUE, 1, 7) = 'TO_DATE' THEN
DBMS_OUTPUT.PUT_LINE(
'La Table: ' ||r.table_owner||'.'|| r.TABLE_NAME || ' est éligible'
);
END IF;
END LOOP;
END;
/

• Récupérer L’ordre DDL complet de création des tables cibles, d’une part pour vérifier les critères de partitionnement, d’autre part pour proposer la modification avec la clause de compression HCC.
Pour chaque table cible :

set long 2000
set pagesize 0
SELECT DBMS_METADATA.GET_DDL('TABLE',’TABLE_NAME’,'TABLE_OWNER’) FROM DUAL ;

Les partitions ou sous-partitions correspondant aux données les plus anciennes sont éligibles à la compression HCC.
• La liste sera triée en fonction de l’espace pris par les segments des partitions ou sous-partitions (espace avant compression)
• Restera à déterminer le taux de compression suivant l’ancienneté et l’usage
 

Tables de chargement temporaire

Les tables temporaires, au sens applicatif, car les tables de type « TEMPORARY » d’Oracle ne peuvent pas être compressées, utilisées pour le chargement / déchargement des données sont des cibles potentielles pour la compression HCC car :
• La méthode d’insertion est en mode direct
• La volumétrie peut être importante
• Elles sont ensuite uniquement accédées en SELECT pour la suite des traitements d’agrégation
Ces tables étant transitoires et supprimées après la procédure, il n’est pas possible d’altérer leur définition. Il faut donc étudier le paramétrage des outils utilisés pour vérifier si le DDL de ces tables peut être modifié pour ajouter une clause de compression.
L’influence du temps de la compression pendant le chargement peut être importante et rendre de toute façon inéligibles ces tables.
 

Autres tables possibles

Dans le cas où le partitionnement n’est pas une option disponible, la compression peut être évaluée sur les critères suivants :
• Tables volumineuses (seuil à déterminer , proposition de départ arbitrairement à 500Mo )
Définition du seuil à 500Mo :

DEFINE SIZETHRE=500

Récupération de la liste des tables concernées :

SELECT A.OWNER,
A.SEGMENT_NAME,
ROUND (BYTES / 1024 / 1024 , 2) SIZE_MO,
B.OBJECT_TYPE
FROM DBA_SEGMENTS A, DBA_OBJECTS B, DBA_TABLES C
WHERE
A.SEGMENT_NAME = B.OBJECT_NAME
AND C.TABLE_NAME = A.SEGMENT_NAME
AND A.OWNER NOT IN &NOTUSERS
AND ROUND (BYTES / 1024 / 1024 , 2) > &SIZETHRE
AND OBJECT_TYPE IN ('TABLE', 'TABLE PARTITION', 'TABLE SUBPARTITION')
ORDER by SIZE_MO,OWNER,SEGMENT_NAME;

• Tables volumineuses et tables d’historique ou de LOG sur lesquelles il y a peu, voire pas de modification. Rechercher HIST ou LOG dans le nom des tables :

SELECT A.OWNER,
A.SEGMENT_NAME,
ROUND (BYTES / 1024 / 1024 , 2) SIZE_MO,
B.OBJECT_TYPE
FROM DBA_SEGMENTS A, DBA_OBJECTS B, DBA_TABLES C
WHERE
A.SEGMENT_NAME = B.OBJECT_NAME
AND C.TABLE_NAME = A.SEGMENT_NAME
AND (UPPER(C.TABLE_NAME) LIKE '%HIST%' OR UPPER(C.TABLE_NAME) LIKE '%LOG%')
AND A.OWNER NOT IN &NOTUSERS
AND ROUND (BYTES / 1024 / 1024 , 2) > &SIZETHRE
AND OBJECT_TYPE IN ('TABLE', 'TABLE PARTITION', 'TABLE SUBPARTITION')
ORDER by SIZE_MO,OWNER,SEGMENT_NAME ;

Requête regroupant critère colonne de type « DATE » ou historique ou log :

SELECT A.OWNER,
A.SEGMENT_NAME,
ROUND (BYTES / 1024 / 1024 , 2) SIZE_MO,
B.OBJECT_TYPE,
PARTITIONED
FROM DBA_SEGMENTS A, DBA_OBJECTS B, DBA_TABLES C
WHERE
A.SEGMENT_NAME = B.OBJECT_NAME
AND C.TABLE_NAME = A.SEGMENT_NAME
AND (C.TABLE_NAME IN (SELECT TABLE_NAME FROM DBA_TAB_COLUMNS WHERE DATA_TYPE LIKE 'TIMESTAMP%' OR DATA_TYPE LIKE 'INTERVAL%' OR DATA_TYPE='DATE')
OR (UPPER(C.TABLE_NAME) LIKE '%HIST%' OR UPPER(C.TABLE_NAME) LIKE '%LOG%'))
AND A.OWNER NOT IN &NOTUSERS
AND ROUND (BYTES / 1024 / 1024 , 2) > &SIZETHRE
AND OBJECT_TYPE IN ('TABLE', 'TABLE PARTITION', 'TABLE SUBPARTITION')
ORDER by SIZE_MO,OWNER,SEGMENT_NAME ;
Tablespace de destination
Le tablespace utilisé comme destination pour les tables avec la compression HCC doit avoir une allocation automatique de la taille extents.
Clause : EXTENT MANAGEMENT LOCAL AUTOALLOCATE;
Et surtout pas une allocation de taille fixe des extents :
Clause : EXTENT MANAGEMENT LOCAL UNIFORM SIZE 128K;
Pour vérifier, voir le contenu de la colonne « ALLOCATION_TYPE » dans DBA_TABLESPACES :
DEFINE TSCIBLE='TSTALLOC'
SELECT TABLESPACE_NAME, EXTENT_MANAGEMENT, ALLOCATION_TYPE FROM DBA_TABLESPACES WHERE TABLESPACE_NAME='TSCIBLE' ;

Le résultat doit être :

TSTALLOC LOCAL SYSTEM

Détermination du taux de compression

Les choix de compression HCC sont les suivants, dans l’ordre croissant du taux de compression :
• Compression pour QUERY
Taux de mise à jour ou évolution des données faibles
– LOW ( 6X)
CREATE TABLE sales_history … COMPRESS FOR QUERY LOW;
Temps de chargement peu impacté.
– HIGH (10X)
CREATE TABLE sales_history … COMPRESS FOR QUERY;
CREATE TABLE sales_history … COMPRESS FOR QUERY HIGH;
Temps de chargement plus élevé, meilleures performances d’accès
• Compression pour ARCHIVE
Performances d’accès faible, données historiques ou d’archives rarement accédées et jamais modifiées.
– LOW (10X)
CREATE TABLE sales_history … COMPRESS FOR ARCHIVE;
CREATE TABLE sales_history … COMPRESS FOR ARCHIVE LOW;
– HIGH (15X)
CREATE TABLE sales_history … COMPRESS FOR ARCHIVE HIGH;
Le taux réel de compression dépend de la typologie des colonnes des tables et de la répartition des données. Un facteur de 10X pour le mode ARCHIVE HIGH est le résultat de la compression chez un de nos clients. Le package DBMS_COMPRESSION donnera une approximation assez fidèle.
Note : la syntaxe à partir de la version 12.1 devient :
CREATE TABLE sales_history … COLUMN STORE COMPRESS FOR … ;
 

Package DBMS_COMPRESSION

Ce package sera utilisé pour estimer le gain en stockage lié à la mise en place de la compression HCC.
L’utilisation du package dépend de la version d’Oracle, en version 12c :

SET SERVEROUTPUT ON
DECLARE
l_blkcnt_cmp PLS_INTEGER;
l_blkcnt_uncmp PLS_INTEGER;
l_row_cmp PLS_INTEGER;
l_row_uncmp PLS_INTEGER;
l_cmp_ratio NUMBER;
l_comptype_str VARCHAR2(32767);
BEGIN
DBMS_COMPRESSION.get_compression_ratio (
scratchtbsname => 'TBS_NAME',
ownname => 'SCHEMA_NAME',
objname => 'TABLE_NAME',
subobjname => NULL,
comptype => DBMS_COMPRESSION.comp_archive_high,
blkcnt_cmp => l_blkcnt_cmp,
blkcnt_uncmp => l_blkcnt_uncmp,
row_cmp => l_row_cmp,
row_uncmp => l_row_uncmp,
cmp_ratio => l_cmp_ratio,
comptype_str => l_comptype_str,
subset_numrows => DBMS_COMPRESSION.comp_ratio_allrows,
objtype => DBMS_COMPRESSION.objtype_table
);
DBMS_OUTPUT.put_line('Number of blocks used (compressed) : ' || l_blkcnt_cmp);
DBMS_OUTPUT.put_line('Number of blocks used (uncompressed) : ' || l_blkcnt_uncmp);
DBMS_OUTPUT.put_line('Number of rows in a block (compressed) : ' || l_row_cmp);
DBMS_OUTPUT.put_line('Number of rows in a block (uncompressed) : ' || l_row_uncmp);
DBMS_OUTPUT.put_line('Compression ratio : ' || l_cmp_ratio);
DBMS_OUTPUT.put_line('Compression type : ' || l_comptype_str);
END;
/

Définir à chaque fois :
• le nom du tablespace utilisé pour le test
• le nom du schéma propriétaire de l’objet
• le nom de la table
• Paramètre comptype : choix du mode de compression, constante :
• DBMS_COMPRESSION.comp_query_low
• DBMS_COMPRESSION.comp_query_high
• DBMS_COMPRESSION.comp_archive_low
• DBMS_COMPRESSION.comp_archive_high
La valeur de la constante « comptype » peut être retrouvée dans la documentation ou être retrouvée par ce genre de select :

SELECT DECODE(DBMS_COMPRESSION.GET_COMPRESSION_TYPE(
ownname => 'HR',
tabname => 'EMPLOYEES',
subobjname => '',
row_id => 'AAAVEIAAGAAAABTAAD'),
1, 'No Compression',
2, 'Advanced Row Compression',
4, 'Hybrid Columnar Compression for Query High',
8, 'Hybrid Columnar Compression for Query Low',
16, 'Hybrid Columnar Compression for Archive High',
32, 'Hybrid Columnar Compression for Archive Low',
4096, 'Basic Table Compression',
'Unknown Compression Type') compression_type
FROM DUAL;

 

Impacts et effets de bord

1) Méthode de chargement des tables

La compression de type HCC n’est optimale que si la table est chargée en mode direct (DIRECT LOAD).
Il faut donc revoir le modèle de chargement utilisé et le modifier si nécessaire et possible.
Rappels des modes compatibles :
• Ordre insert avec le hint « APPEND »
• Opération de chargement parallèle
• SLQ*Loader en mode direct
• Ordre de type « CREATE TABLE AS SELECT »
 

2) Performances

L’impact sur les performances est important, il peut être bénéfique pour les opérations de lecture et très négatif sur les activités transactionnelles.
Il est important de ne pas faire du systématique dans la mise en place de la compression HCC sous peine de se retrouver avec des applications inutilisables.
Opérations de type DML
Sur une opération de mise à jour d’une ligne dans une table compressée par HCC, il se déroule une suppression suivie d’une insertion, ce qui a pour incidence pour la ligne :
• Changement d’identifiant, le ROWID n’est plus le même, les indexes associés se mettent à jour
• Les données de la ligne sortent du bloc de compression et sont stockées dans un autre bloc au format de compression OLTP (avec un identifiant de compression différent du format compression OLTP de l’option ACO pour ne pas enfreindre les règles de licencing) .
Pour plus de détail, se reporter à la note MOS :
« 1332853.1 How Hybrid Columnar Compression Works When Rows are Inserted/Updated. »
Le mécanisme de verrouillage change : le niveau le plus bas devient le CU (Compression Unit) au lieu du niveau ligne d’où une contention beaucoup plus forte sur les transactions avec une montée significative des attentes de type « row lock contention ».
Statistiques pour l’optimiseur
Le nombre de blocs composant la table devenant plus faible que celui d’origine, la valeur calculée pour les plans d’exécution va être impactée et les choix de l’optimiseur être différents.
Il va être important, avant de mettre en place la compression, de repérer les requêtes qui accèdent les tables cibles ainsi que le plan et les statistiques d’exécution et de s’en faire un point de référence.
Ces mêmes requêtes une fois la compression réalisée seront à analyser et comparer pour valider l’impact de la compression, cet élément sera un point clé d’un rapport d’impact.
 

3) Interaction avec les autres fonctionnalités

a) Transfert et sauvegarde de données

– Export et Import
Par défaut, l’opération d’import via impdp conserve les propriétés de compression de la table.
Si le tablespace de destination n’est pas compatible ou ne supporte pas la compression de type HCC (destination sur une architecture non supportée pour HCC), la commande d’import s’arrête en erreur.
L’import d’une table utilisant à l’origine la compression HCC en tant que table non compressée peut se faire avec la clause « TRANSFORM=SEGMENT_ATTRIBUTES:n », où les définitions particulières de stockage ne sont pas prises en compte et où s’appliqueront les clauses de stockage du tablespace de destination.
– Sauvegarde et restauration RMAN
La sauvegarde et la restauration RMAN se faisant au niveau du bloc, les informations compressées au départ seront donc compressées dans le jeu de sauvegarde ou dans la copie RMAN et se retrouveront donc compressées à la restauration.
Si la restauration se fait sur une architecture non compatible HCC :
Pas d’erreur pendant la restauration et la récupération RMAN (traitement niveau bloc)
Par contre, sur tentative d’accès par SQL aux données de la table, on obtient en retour l’erreur :

ORA-64307: hybrid columnar compression is only supported in tablespaces
residing on Exadata storage

Pour se sortir de cette erreur et retrouver l’accès aux données :
• Changer la définition de la compression pour la table|partition|subpartition en NOCOMPRESS
• Faire un ALTER TABLE|PARTITION|SUBPARTITION … MOVE pour réaliser la décompression sur les données existantes.
• Exemple pour les partitions d’une table TESTCOMP
• Modification de la clause de stockage :

SQL> ALTER SESSION ENABLE PARALLEL DDL;
SQL> ALTER TABLE TESTCOMP MODIFY PARTITION SYS_P61985 NOCOMPRESS;
SQL> ALTER TABLE TESTCOMP MODIFY PARTITION SYS_P61986 NOCOMPRESS;
SQL> ALTER TABLE TESTCOMP MODIFY PARTITION SYS_P61987 NOCOMPRESS;
SQL> ALTER TABLE TESTCOMP MODIFY PARTITION SYS_P61988 NOCOMPRESS;

• Décompression des partitions :

SQL> ALTER TABLE TESTCOMP MOVE PARTITION SYS_P61985 PARALLEL;
SQL> ALTER TABLE TESTCOMP MOVE PARTITION SYS_P61986 PARALLEL;
SQL> ALTER TABLE TESTCOMP MOVE PARTITION SYS_P61987 PARALLEL;
SQL> ALTER TABLE TESTCOMP MOVE PARTITION SYS_P61988 PARALLEL;

Note : Les indexes associés doivent ensuite être reconstruits

b) Réplication

– Dataguard
Dans le cadre d’une base de secours physique, les blocs entre les sites sont exactement les mêmes ce qui veut dire que si d’un côté l’architecture est compatible HCC et pas de l’autre, le mécanisme de réplication va fonctionner, mais en cas de bascule ou d’utilisation de la base de secours on retombera sur l’erreur précédente :

ORA-64307: hybrid columnar compression is only supported in tablespaces residing on Exadata storage

Dont on ne pourra se sortir que par la même méthode :
• Changer la définition de la compression pour la table|partition|subpartition en NOCOMPRESS
• Faire un ALTER TABLE|PARTITION|SUBPARTITION … MOVE pour réaliser la décompression sur les données existantes.
• Reconstruction des indexes associés
Ce qui, dans le cadre d’un PRA, induit un temps incompatible avec la fonctionnalité et nécessite d’avoir l’espace nécessaire sur le site de secours pour accepter la décompression des données.
– Golden Gate
En cas d’usage de la compression HCC sur la source, il faut que la capture soit en mode « INTEGRATED CAPTURE »
• La compression HCC n’est pas supportée en mode « CLASSIC CAPTURE »
• Pour la réplication sur la cible vers une architecture compatible HCC et une table définie pour la compression HCC, utiliser le paramètre « INSERTAPPEND » dans le fichier de paramètre du réplica, ce qui positionne le hint /*+ APPEND */ pendant l’insertion et permet la compression des informations. Dans le cas contraire, les données ne seraient pas compressées.
c) Cryptage
• Les deux fonctionnalités sont compatibles l’une avec l’autre.
• Pas d’incompatibilité détectée.
 

Méthodes d’implémentation

1) EXPORT / IMPORT DATAPUMP

Vision de la table au moment de l’export, aucune transaction sur la table pendant l’opération.
Sur la commande import :
• Soit on crée au préalable la table avec la clause de compression puis on importe uniquement les données.
• Soit on définit une valeur de compression par défaut pour le tablespace de destination
ALTER TABLESPACE … SET DEFAULT COMPRESS QUERY et on utilise la clause
• Et on ne prend pas en compte les éléments de la clause de stockage de la table avec la clause :
TRANSFORM =SEGMENT_ATTRIBUTES:n
• Soit depuis la version 12.1 :
TRANSFORM=TABLE_COMPRESSION_CLAUSE:[NONE | compression_clause]
Les valeurs possibles pour TABLE_COMPRESSION_CLAUSE étant :
• NONE : Pas de prise en compte des caractéristiques de compression de la table, les caractéristiques par défaut du tablespace sont prises en compte
• NOCOMPRESS : Désactivation de la compression.
• COMPRESS : Mise en œuvre de la compression BASIC .
• ROW STORE COMPRESS BASIC : Identique à COMPRESS.
• ROW STORE COMPRESS ADVANCED : Mise en œuvre de la compression avancée ou compression OLTP
• COLUMN STORE COMPRESS FOR QUERY : Hybrid Columnar Compression (HCC) mode QUERY .
• COLUMN STORE COMPRESS FOR ARCHIVE : Hybrid Columnar Compression (HCC) mode ARCHIVE
Exemple :

$ impdp system/Password1@pdb1 directory=test_dir dumpfile=emp.dmp logfile=impdp_emp.log remap_schema=scott:test transform=table_compression_clause: 'COLUMN STORE compress FOR ARCHIVE'

Normalement, impdp choisit le mode de chargement de l’import automatiquement et fait du chargement en mode DIRECT (recommandé pour la compression) si un certain nombre de conditions sont remplies (Pas de colonne cryptée, pas de supplemental logging sur la base, pas de colonne de type BLOB, etc.). Le mode peut être forcé via l’option cachée de la commande : « ACCESS_METHOD=DIRECT_PATH »
L’option de trace : « TRACE=400300 » permet d’ajouter dans la trace du processus qui fait l’import le modèle de chargement choisi.

2) Redéfinition en ligne (DBMS_REDEFINITION)

• Compression des lignes existantes ainsi que pour les futures insertions
• La table reste en ligne et accessible en lecture et en écriture pendant toute l’opération.
• L’opération peut se faire en parallèle pour un gain de temps.
• Le processus maintient les indexes pendant toute l’opération sauf dans le cas d’index globaux de tables partitionnées qui deviennent invalides et qu’il faut reconstruire.
Les étapes nécessaires pour réaliser l’opération en utilisant une table nommée ORIGINAL non compressée, dont on regarde en amont le nombre d’extents qui la constitue :

SQL> SELECT COUNT(*) FROM USER_EXTENTS WHERE SEGMENT_NAME = 'ORIGINAL';

• Créer une table d’intérim de même structure que la table d’origine qui va être définie avec la clause de compression

SQL> CREATE TABLE INTERIM AS SELECT * FROM ORIGINAL WHERE 1=2 COMPRESS FOR QUERY LOW ;

• Vérifier la possibilité d’utiliser le package DBMS_REDEFINITION avec la table d’origine

SET SERVEROUTPUT ON
BEGIN
DBMS_REDEFINITION.CAN_REDEF_TABLE('TEST','ORIGINAL', DBMS_REDEFINITION.CONS_USE_ROWID);
END;
/

• Commencer le processus de redéfinition

BEGIN
DBMS_REDEFINITION.START_REDEF_TABLE(
uname => 'TEST',
orig_table => 'ORIGINAL',
int_table => 'INTERIM',
options_flag => DBMS_REDEFINITION.CONS_USE_ROWID);
END;
/

• Copier les éléments dépendant de la table d’origine vers l’autre (INDEX, contraintes …)

DECLARE
ERROR_COUNT PLS_INTEGER := 0;
BEGIN
DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS('TEST', 'ORIGINAL', 'INTERIM', DBMS_REDEFINITION.CONS_ORIG_PARAMS, TRUE,TRUE,TRUE,FALSE, ERROR_COUNT);
DBMS_OUTPUT.PUT_LINE('ERRORS := ' || TO_CHAR(ERROR_COUNT));
END;
/

• Réaliser une synchronisation intermédiaire des deux tables avant de terminer

BEGIN
DBMS_REDEFINITION.SYNC_INTERIM_TABLE('TEST', 'ORIGINAL', 'INTERIM');
END;
/

• Terminer l’opération de redéfinition

EXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE('TEST','ORIGINAL','INTERIM');

• Vérifier le nombre d’extents associés

SELECT COUNT(*) FROM USER_EXTENTS WHERE SEGMENT_NAME = 'ORIGINAL';

 

3) ALTER TABLE … COMPRESS FOR …

• Validation de la compression pour les futures insertions
• Les données actuelles de la table ne sont pas modifiées

SQL> ALTER TABLE ORIGINAL COMPRESS FOR ARCHIVE HIGH ;

Une commande « ALTER TABLE … MOVE » peut ensuite faire l’opération de compression sur toute la table.
 

4) ALTER TABLE … MOVE COMPRESS FOR …

Compression des lignes existantes ainsi que pour les futures insertions
• La table reste en ligne et accessible en lecture seulement, un verrou exclusif est posé sur la table pendant la durée de l’opération
• Attention, les opérations de type ALTER MOVE rendent les indexes associés UNUSABLE, il faut donc les reconstruire les indexes ensuite.
• Pour l’utilisation avec une table partitionnée, la clause UPDATE INDEXES permet de maintenir les indexes qui restent ainsi opérationnels, mais là aussi un verrou exclusif est posé.

SQL> ALTER TABLE ORIGINAL MOVE COMPRESS FOR QUERY HIGH ;
SQL> ALTER TABLE ORIGINAL MOVE PARTITION P1 COMPRESS FOR ARCHIVE HIGH ;

 

5) ALTER TABLE … MOVE PARTITION ONLINE

• Compression des lignes existantes ainsi que pour les futures insertions
• La table reste en ligne et accessible en lecture et en écriture pendant toute l’opération
• Le processus maintient les indexes pendant toute l’opération
• La possibilité ALTER TABLE…MOVE TABLE ….ONLINE apparait seulement en version 12.2

SQL> ALTER TABLE ORIGINAL MOVE COMPRESS FOR QUERY HIGH ONLINE ;

• Uniquement pour les partitions ou sous-partitions en version 11.2 et 12.1

SQL> ALTER TABLE ORIGINAL MOVE PARTITION P1 COMPRESS FOR ARCHIVE HIGH ONLINE;

 

Suivi de l’implémentation

Une fois l’implémentation de la compression réalisée, il faudra fournir un rapport d’impact qui devra indiquer au moins les éléments suivants pour chaque table cible de la compression HCC :
• Schéma,
• Nom de table,
• Taille initiale,
• Taille compressée,
• Écart performance en requête,
• Écart performance en DML.
Ainsi qu’un statut qui permettre de valider la compression ou de revenir en arrière.
 

Evolution du stockage dans le temps

Pour chaque table cible de la compression HCC, la surveillance de l’évolution du stockage aura son importance, surtout si la table est vivante et non partitionnée.
Pour rappel, les mises à jour sont impactantes sur la volumétrie, de même que les insertions qui ne seraient pas réalisées en mode direct, de nouveaux blocs étant attribués au segment et les lignes pas nécessairement compressées dans ces blocs.
D’où la nécessité de consulter régulièrement le nombre d’extents pris pour la table dans DBA_SEGMENTS.
 

Statistiques à superviser

Sans être exhaustif et loin s’en faut, les statistiques les plus importantes dans le cadre de la mise en place de la compression HCC sont :
• CPU utilisé par la base : les activités de compression et de décompression ont un impact sur l’activité CPU
• Logical reads : Le nombre de blocs manipulés doit diminuer suite à la compression des données.
• Row lock contention : Nombre de verrous posés sur les lignes, en augmentation une fois la compression HCC en place puisque ce sont toutes les lignes d’une CU (compression unit) qui sont verrouillées.