samedi 4 octobre 2014

Compression: retour d'expérience

A l’époque de l’explosion des données ( big data ), il m’a semblé intéressant de mettre en place la compression sur une instance de production ( 11gR2 ), afin de la valider en particulier au niveau des tables, la compression FOR OLTP étant l’objet de nombreux doutes.

J’ai commencé par mettre en œuvre la compression des index ( 9i ) encore assez méconnue. Pour commencer, j’ai estimé le gain potentiel sur les index dépassant une certaine taille, dans le cas présent 2 GB. Pour ce faire, on utilise la commande suivante : 
            analyze index index_name validate structure;
Les colonnes OPT_CMPR_COUNT et OPT_CMPR_PCTSAVE permettent de définir le nombre de colonnes de l’index à spécifier pour la compression et le gain en pourcentage. L’estimation fournie est très satisfaisante suite à mes tests.

Pour activer la compression sur un index, on peut lancer les deux commandes suivantes : 
           alter index index_name rebuild online compress parallel n; 
           alter index index_name  noparallel;

Pour visualiser les index compressés, on exécute la commande suivante: 
           select * from user_indexes where compression = 'ENABLED' order by index_name;
Et pour vérifier le gain réel, on utilise la vue user_segments.

Comme pour les tables, la compression des index permet de réduire la place disque occupée par ces objets mais aussi de diminuer les IO disque au niveau de l'instance.

La compression FOR OLTP pour les tables est, quant à elle, plus délicate à aborder. Avant de l’installer, je vous conseille de lire l’article écrit par J.Lewis afin d’en appréhender les limites : http://allthingsoracle.com/compression-in-oracle-part-3-oltp-compression/ . En particulier, il est intéressant de noter qu’elle est active pour tous les types d’insert, une fois le PCT_FREE atteint. En revanche, elle ne s’active pas lorsqu’une mise à jour concerne les tokens se trouvant dans la table des symboles du bloc de données. Dans ce cas, on peut même observer une décompression des tokens pouvant occasionner des migrations de lignes. Pour ma part, je n’observe pas ce genre de phénomène, mais je reste vigilant sur le sujet, la compression venant d’être mise en place.

Pour estimer le gain apporté par la compression sur une table, on utilise la méthode get_compression_ratio :
alter session set NLS_NUMERIC_CHARACTERS='.,'; => sinon, erreur ORA
set serveroutput on size unlimited
declare
   v_blkcnt_cmp pls_integer;
   v_blkcnt_uncmp pls_integer;
   v_row_cmp pls_integer;
   v_row_uncmp pls_integer;
   v_cmp_ratio number;
   v_comptyp_str varchar2(80);
begin
   dbms_compression.get_compression_ratio(scratchtbsname=>'tablespace_name',
                                          ownname=>'user_name',
                                          tabname=>'table_name',
                                          partname=>NULL,
                                          comptype=>dbms_compression.comp_for_oltp,
                                          blkcnt_cmp => v_blkcnt_cmp,
                                          blkcnt_uncmp => v_blkcnt_uncmp,
                                          row_cmp=> v_row_cmp,
                                          row_uncmp=> v_row_uncmp,
                                          cmp_ratio=> v_cmp_ratio,
                                          comptype_str => v_comptyp_str);
    dbms_output.put_line(to_char(v_blkcnt_cmp));
  
end;

J’ai trouvé l’estimation fournie décevante, souvent sous-évaluée. Si possible, un export/import de la table est souhaitable pour se faire une meilleure idée du taux de compression.

Le segment advisor fournit des tables candidates à la compression FOR OLTP. Initialement, j’ai aussi sélectionné les tables de plus de 8 GB pour identifier d’autres compressions possibles.

Pour compresser une table, vous avez trois principales méthodes : 
              alter table table_name move compress for oltp;
              utilisation du package dbms_redefinition; 
              alter table table_name compress for oltp.
 La première méthode est intéressante pour estimer réellement le taux de compression sur un environnement de test. Mais elle n’est pas online et il faut reconstruire les index par la suite.
La seconde méthode est online, mais je la trouve très lourde à mettre en œuvre. C’est pourquoi j’ai opté pour la troisième méthode en production, sachant que la compression ne s’appliquera que sur les nouveaux blocs. Pour les blocs existants, la purge permettra leur suppression.

Il y a peu de statistiques disponibles pour suivre la compression des tables :
select *
from V$SYSSTAT ( => dba_hist_sysstat )
where ( name like 'HSC%' or name = 'Heap Segment Array Inserts')
order by statistic#;

HSC OLTP Compressed Blocks: how many blocks are compressed using OLTP Compression. Counts only the first compressions in OLTP code
HSC OLTP Space Saving:  how many bytes saved in total using OLTP Compression.
HSC IDL Compressed Blocks: number of Blocks compressed using Insert Direct Load
HSC Compressed Segment Block Changes: total number of block changes to Tables/Heaps (Compressed only)
HSC Heap Segment Block Changes: total number of block changes to Tables/Heaps (Compressed or Non-Compressed)
HSC OLTP Non Compressible Blocks: blocks marked as Final (Not to be compressed again)
HSC OLTP Compression skipped rows: number of rows that are skipped for compression (could be deleted or chained)