vendredi 16 janvier 2015

Histogramme: comment les décrypter

Un histogramme sur une colonne peut être utile si cette colonne a une distribution non uniforme de ses valeurs; on parle alors de skew distribution. Jusqu'à la 12c, il existait deux types d'histogramme: les histogrammes de type fréquence et les histogrammes de type height-balanced. Les premiers, sorte de diagramme en bâton, sont précis, mais ils sont limités à 256 valeurs. Les seconds, se basant sur un algorithme d'identification de valeurs populaires,  permettent de traiter les autres cas, mais ils peuvent être amenés à être imprécis pour certains types de distribution. Lorsque cela se produit, soit on supprime l'histogramme, soit on le fake si les données ont une certaine stabilité dans le temps.

Mais, avant de mettre en défaut un histogramme, il est utile de pouvoir le décrypter ( ! ) afin de vérifier sa validité. En effet, la lecture d'un histogramme est parfois tout sauf une chose aisée. Afin de vous aider dans cette tâche, j'ai chargé dans Google Drive un fichier exemple ( /oracle/histogram/etude_histogram.sql ). Sur ce point, un grand merci à J.Lewis, comme d'habitude ...

Depuis la 12c, on peut désormais avoir 2048 valeurs dans un histogramme de type fréquence. De plus, deux nouveaux types d'histogramme sont apparus: les histogrammes de type top frequency et les histogrammes hybrides.  Les premiers sont très intéressants car ce sont des histogrammes de type fréquence qui regroupe les top-n valeurs d'une colonne, ce qui est souvent représentatif de la réalité ( penser à une distribution de Zipfian pour simuler ce genre de colonne ). Les seconds sont une amélioration des histogrammes de type height-balanced.

Si vous souhaitez avoir plus d'infos sur ce sujet et plus généralement sur les nouveautés de la 12c au niveau de l'optimiseur: /oracle/paris_oracle_meetup/The Query Optimizer in Oracle Database 12c - What's new ? ( written by C.Antognini ).

Jusqu'à maintenant, je vous ai parlé d'histogramme sur une colonne. Ce type d'outil reste valide tant que les valeurs des colonnes sont indépendantes les unes des autres. Mais quand cela n'est plus le cas, l'optimiseur ne peut plus estimer correctement la sélectivité d'une clause where comportant par exemple deux colonnes dépendantes l'une de l'autre. Pour pallier ce défaut, Oracle a introduit en 11g la notion d'extended statistics.

Oracle implémente cette notion en créant une colonne virtuelle correspondant à la concaténation des colonnes ciblées, puis calcule les statistiques sur la colonne virtuelle: on peut alors obtenir un histogramme sur plusieurs colonnes. La colonne virtuelle est définie via la fonction sys_op_combined_hash.

Enfin, pour finir, SVP, ne supprimer pas les histogrammes d'une base sans raison !


jeudi 8 janvier 2015

Liens invalides

Dernièrement, Free a interdit la lecture des répertoires sur les sites FTP perso à la demande de la CNIL. Par conséquent, seuls les liens sur un fichier fonctionnent désormais.

Pour les liens sur les répertoires, je les ai remplacés par un accès en mode public via google drive. Ils sont désormais au niveau des posts de mon compte Google+.

Désolé.

mardi 30 décembre 2014

Bases colonnes

Les bases colonnes émergent petit à petit dans le monde de l'entreprise, suite à de nombreuses recherches universitaires effectuées au début des années 2000. Il y a quelques années, SAP a mis sur le marché HANA, un moteur in-memory reposant sur un modèle colonne ( le modèle ligne est encore disponible au cas où ). Puis, des sociétés comme HP ( Vertica ) ou Oracle ( option in-memory ) ont proposé des solutions alternatives.

Ce modèle permet d'offrir une nouvelle alternative pour l'OLAP, SAP ayant même l'objectif d'en faire une base "universelle" ( OLAP + OLTP ). Oracle propose quant à lui d'utiliser la base en mode ligne pour l'OLTP et la base en mode colonne pour l'OLAP. De cette manière, de nombreux index peuvent être supprimés, une table en mode colonne ne nécessitant pas d'index, ce qui soulage la partie OLTP pour les mises à jour. De plus, les datamarts peuvent être ramenés au niveau des bases OLTP, le tout étant chargé en RAM.

Les caractéristiques principales d'une base colonne sont les suivantes:
- une compression par colonne permettant des taux de compression parfois impressionnants sur certaines colonnes;
- une vectorisation des données permettant d'exploiter les instructions SIMD des nouveaux processeurs;
- une localité différente des données ( les données sont au pire en RAM et non plus sur le disque ).

Ces propriétés permettent de traiter les requêtes analytiques de manière très efficace si ces dernières portent sur un nombre de colonnes raisonnable. Ce modèle, contrairement à de nombreuses bases nosql, autorisent aussi les jointures.

A ce jour, il reste à vérifier si ce modèle peut s'étendre à l'OLTP de manière satisfaisante. Pour ce faire, SAP a par exemple ajouté une zone delta en mode ligne pour optimiser ses mises à jour unitaires.

Pour aller plus loin, je vous conseille la lecture du ce document :
         The Design and Implementation of Modern Column-Oriented Database System
         D.Abadi, P.Boncz, S.Harizopoulos, S.Idreos, S.Madden


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)

dimanche 3 août 2014

OCI: si possible, utiliser l'OCILIB

Dernièrement, j'ai travaillé sur une interface C écrite en OCI natif. Sans rentrer dans les détails, elle était d'une piètre qualité, en particulier les requêtes n'étaient pas bindées ...

Si vous avez le choix, je vous conseille vivement d'utiliser l'OCILIB plutôt que d'attaquer directement la couche native. Dans le cas contraire, inspirez-vous du code source de l'OCILIB disponible à cette adresse. Des exemples sont également fournis dans la doc officielle.

Mais de grâce, ne réinventez pas la roue !

Si vous avez besoin d'un bulk collect en OCI, voici un exemple.


lundi 9 juin 2014

Cassandra

Une présentation de Cassandra ( version 2.0 ), une base nosql hybride.

Cassandra est un moteur in-memory pour l'écriture. Couplé à un produit libre comme Spark pour la lecture, on aboutit à une solution full in-memory, ce qui change la donne en terme de performance.
 

jeudi 17 avril 2014

MongoDB

Une présentation de MongoDB ( version 2.4 ) ,  une base nosql orientée document.