Dans le contexte actuel d’accroissement rapide du volume des informations stockées dans nos bases de données de prédilection (je fais évidemment ici référence à ORACLE), il peut devenir très difficile d’extraire certaines informations dans les temps imposés pour des besoins particuliers.
Certaines décisions ne peuvent pourtant pas toujours attendre plusieurs heures voire plusieurs jours dans certains cas, lorsque des requêtes décisionnelles doivent manipuler plusieurs « terabytes » de données.
Lorsque les possibilités d’optimisations des traitements métiers ou d’adaptations architecturales (utilisation de l’option « partitioning » par exemple) ne suffisent plus à répondre à cette problématique de temps de réponse, plusieurs solutions matérielles (solutions de stockage à haute performance / utilisation d’Engineered Systems / etc …) peuvent être envisagées mais plusieurs facteurs (coûts / choix imposés par l’hébergeur / etc …) ne permettent pas toujours de s’y orienter aisément.
ORACLE propose une solution logicielle, sous la forme d’une option utilisable avec la version 12c de son SGBD : Oracle 12c In-Memory (Option « In Memory Database Cache » dans le catalogue des prix).
Oracle l’a présenté à ses partenaires lors des animations Techn’Oracle et Easyteam vous en a fait le compte-rendu ici.
Dans cet article, nous allons voir comment configurer l’utilisation de cette option, en travaillant dans une base de données mono-instance ORACLE 12.1.0.2 EE.
1) Dans un premier temps, nous allons activer la possibilité technique d’utiliser le « In Memory Column Store » :
La configuration de l’option se fait simplement en positionnant la valeur du paramètre d’initialisation « inmemory_size », qui par défaut est égale à « 0 ».
Ce paramètre agit sur la taille à attribuer au buffer statique (= Non gérable dynamiquement via « AMM » ou « ASMM ») nommé « In Memory » ou plus simplement « IM » dans la suite.
SQL> show parameter inmemory_size; NAME TYPE VALUE ------------------------------------ ----------- ----- inmemory_size big integer 0 SQL> alter system set inmemory_size=5G scope=spfile; SQL> shutdown immediate; (...) SQL>startup; (...)
Suite au redémarrage de notre base de données, le buffer « In Memory » est actif et dispose de 5Go d’espace :
SQL> show parameter inmemory; NAME TYPE VALUE ------------------------------------ ----------- -------- inmemory_clause_default string inmemory_force string DEFAULT inmemory_max_populate_servers integer 12 inmemory_query string ENABLE inmemory_size big integer 5G inmemory_trickle_repopulate_servers_ integer 1 percent optimizer_inmemory_aware boolean TRUE
Attardons-nous un instant sur les 6 autres paramètres mentionnés ci-dessus :
– « inmemory_clause_default » agit sur le comportement par défaut lors des créations des nouveaux objets (dans un souci de simplification, nous parlerons ci-après uniquement du cas des tables).
Par exemple, on pourrait souhaiter que toute nouvelle table créée soit automatiquement placée dans le buffer « IM », il faudrait alors positionner « inmemory_clause_default » à la valeur « INMEMORY ».
Par défaut la valeur de « inmemory_clause_default » est égale à « NULL », ce qui signifie que seules les tables sur lesquelles on agira explicitement dans ce sens (via une commande « ALTER » ou avec l’attribut positionné à la création) seront placées dans le buffer « IM ».
– « inmemory_force »
Par défaut, tout objet incluant l’attribut « INMEMORY » est candidat à l’intégration dans le buffer « IM ».
Cependant, si ce paramètre « inmemory_force » était positionné à la valeur « OFF », aucun objet ne serait placé dans le buffer « IM ». Autrement dit, cela reviendrait à désactiver techniquement l’utilisation de l’option.
– « optimizer_inmemory_aware »
Ce paramètre agit directement sur le comportement de l’optimiseur de sélection de plans. Si la valeur « FALSE » était positionnée, l’optimiseur ne tiendrait plus compte du fait qu’un objet se trouve dans le buffer « IM », lors de ses calculs de plans d’exécutions.
Les paramètres « inmemory_max_populate_servers » et « inmemory_trickle_repopulate_servers_percent » agissent sur le comportement des processus invoqués lors des phases de migrations des informations des segments vers le buffer « IM ».
Le paramètre « inmemory_query » permet d’autoriser ou non l’utilisation de « IM », aussi bien au niveau système qu’au niveau « sessions ».
2) Maintenant que le contexte nous permet l’utilisation de l’option, nous allons illustrer son fonctionnement par l’exemple :
A) Créons une table avec un peu de données dans un des schémas de notre base de données :
SQL> CREATE TABLE "MATABLE" ("MACOLONNE1" VARCHAR2(10), "MACOLONNE2" VARCHAR2(10), "MACOLONNE3" VARCHAR2(10), CONSTRAINT "MATABLE_PK" PRIMARY KEY ("MACOLONNE1") ) TABLESPACE "USERS"; Table created. SQL> insert into MATABLE values ('A','B','C'); 1 row created.
B) Interrogeons les champs de la vue « user_tables » relatifs à l’option « IN MEMORY » et concernant la table qui vient d’être créée :
SQL> select cache, inmemory, inmemory_priority, inmemory_distribute, inmemory_compression from user_tables where table_name like 'MATABLE'; CACHE INMEMORY INMEMORY INMEMORY_DISTRI INMEMORY_COMPRESS ----- -------- -------- --------------- ----------------- N DISABLED
Nous constatons que notre table n’est pour l’instant pas candidate au stockage en mémoire (« INMEMORY » = « DISABLED »).
Cela est logique, dans le sens où la valeur du paramètre « inmemory_clause_default » précédemment mentionné est restée égale à sa valeur par défaut (« NULL »).
Une interrogation de cette table va donc pour l’instant engendrer la génération d’un plan d’exécution classique de parcours complet de la table dans notre contexte :
SQL> select * from MATABLE; MACOLONNE1 MACOLONNE2 MACOLONNE3 ---------- ---------- ---------- A B C | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time -------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 21 | 2 (0)| 00:00 :01 | | 1 | TABLE ACCESS FULL| MATABLE | 1 | 21 | 2 (0)| 00:00 :01 | --------------------------------------------------------------------------------
C) Rendons désormais cette table candidate au stockage en mémoire :
Cela se fait tout simplement en exécutant cet ordre SQL :
SQL> alter table MATABLE CACHE INMEMORY; Table altered.
En faisant cela, nous autorisons ORACLE à placer la table dans le buffer « IM », au moment opportun (= La table ne résidera pas forcément en permanence en mémoire).
Nous pouvons confirmer la bonne prise en compte de cette modification, en exécutant de nouveau la requête de tout à l’heure :
SQL> select cache, inmemory, inmemory_priority, inmemory_distribute, inmemory_compression from user_tables where table_name like 'MATABLE'; CACHE INMEMORY INMEMORY INMEMORY_DISTRI INMEMORY_COMPRESS -------------------- -------- -------- --------------- ----------------- Y ENABLED NONE AUTO FOR QUERY LOW
Par défaut, « INMEMORY_PRIORITY » est positionné à « NONE » ce qui signifie que typiquement, ORACLE placera la table dans le buffer « IM » suite à son premier accès.
Il est possible de modifier la valeur de ce paramètre afin que la table soit, par exemple, directement placée dans le buffer « IM » au démarrage de la ou des instances.
Le paramètre « INMEMORY_DISTRIBUTE » est quant à lui utile dans un environnement de type « RAC ». Dans ce contexte, chaque instance dispose de son propre buffer « IM » et il est possible que chacun d’eux héberge des objets complètement différents (c’est d’ailleurs le comportement par défaut).
Grâce à ce paramètre, on pourrait très bien choisir de répartir équitablement les « large objects » dans l’ensemble des buffers « IM » d’un cluster, voir de disposer de l’ensemble des objets dans chacun d’eux (cette dernière possibilité n’étant néanmoins envisageable que dans le cadre de l’utilisation d’un « Engineered System » (type « EXADATA » par exemple)).
Dans le buffer « IM », chaque objet est compressé. Le niveau de compression est configurable via le paramètre « INMEMORY_COMPRESSION » et a par défaut la valeur « FOR QUERY LOW », le meilleur compromis entre taux de compression et performance.
D) Interrogeons une nouvelle fois notre table, maintenant qu’elle est candidate au stockage en mémoire :
SQL> select * from MATABLE; MACOLONNE1 MACOLONNE2 MACOLONNE3 ---------- ---------- ---------- A B C | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time -------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 21 | 1 (0)| 00:0 0:01 | | 1 | TABLE ACCESS INMEMORY FULL| MATABLE | 1 | 21 | 1 (0)| 00:0 0:01 | --------------------------------------------------------------------------------
Nous constatons d’ores et déjà (du fait de la présence de l’opération « TABLE ACCESS INMEMORY FULL » dans le plan d’exécution généré par l’optimiseur de sélections) le fait que la table a été placée en mémoire lors de ce premier accès.
Cela a été effectué par les process d’arrière-plan nommés « worker proceses », dont le comportement est contrôlable, entre autres possibilités, via les paramètres « inmemory_max_populate_servers » et « inmemory_trickle_repopulate_servers_percent » évoqués plus haut.
E) Contrôlons désormais le status de la migration de notre table vers le buffer « IM », via la vue v$IM_SEGMENTS :
SQL> select v.segment_name name, v.populate_status status, v.bytes_not_populated from v$im_segments v where v.segment_name like 'MATABLE' : NAME -------------------------------------------------------------------------------- STATUS BYTES_NOT_POPULATED --------- ------------------- MATABLE COMPLETED 0
La valeur du champ « BYTES_NOT_POPULATED » est égale à « 0 ». Cela signifie que la totatilité des données de notre table est actuellement présente en mémoire.
La description de cette vue « v$im_segments« , nous fait entrevoir les possibilités qu’elle offre :
SQL> desc v$im_segments; Name Null? Type ----------------------------------------- -------- ---------------------------- OWNER VARCHAR2(128) SEGMENT_NAME VARCHAR2(128) PARTITION_NAME VARCHAR2(128) SEGMENT_TYPE VARCHAR2(18) TABLESPACE_NAME VARCHAR2(30) INMEMORY_SIZE NUMBER BYTES NUMBER BYTES_NOT_POPULATED NUMBER POPULATE_STATUS VARCHAR2(9) INMEMORY_PRIORITY VARCHAR2(8) INMEMORY_DISTRIBUTE VARCHAR2(15) INMEMORY_DUPLICATE VARCHAR2(13) INMEMORY_COMPRESSION VARCHAR2(17) CON_ID NUMBER
F) Qu’en est-il de la compression des données relatives à notre table dans le buffer « IM » :
select v.segment_name, v.bytes orig_size, v.inmemory_size in_mem_size, round(v.bytes / v.inmemory_size, 2) comp_ration from v$im_segments v where v.segment_name like 'MATABLE'; SEGMENT_NAME ---------------------------------- ORIG_SIZE IN_MEM_SIZE COMP_RATION ---------- ----------- ----------- MATABLE 21 11 48
Nous remarquons que, sans avoir agi sur le paramètre « INMEMORY_COMPRESSION » évoqué plus haut, notre table prend par défaut deux fois moins de place en mémoire que sur disque (la compression par défaut est bien utilisée).
3) En conclusion, nous avons pu remarquer que la configuration du « In Memory Column Store » se fait très simplement et rapidement, en positionnant à minima le paramètre d’initialisation « INMEMORY_SIZE« .
Une fois ce dernier positionné, il est également aisé de rendre une table (existante ou nouvelle) candidate au stockage en mémoire.
Une fois cela fait, et si tant est que la paramètre d’initialisation nommé « optimizer_inmemory_aware » soit resté positionné à sa valeur par défaut (« TRUE »), des gains très importants en performance se feront alors directement ressentir lors de certaines interrogations faites sur une telle table (voir l’opération « TABLE ACCESS INMEMORY FULL » du plan d’exécution mentionné au chapitre « 2-D » de cet article), si tant est qu’elle soit bien entendu volumineuse.
Il faut savoir que la fonctionnalité « In-Memory » va être améliorée en 12.2 (ces améliorations étant d’ailleurs une des principales attentes de cette version, non disponible à l’heure à laquelle est écrit cet article).
Mes prochains articles pourraient traiter plus particulièrement des gains en performance apportés par cette nouvelle fonctionnalité, avec des exemples plus concrets de requêtes type décisionnelles sollicitant des tables de plusieurs millions d’enregistrements.
D’autres sujets qui gravitent autours de cette nouvelle fonctionnalité pourraient également être abordés plus tard (« In-Memory Advisor », « In-Memory Transaction Manager », etc …).
—
Vous souhaitez monter en compétences sur la version 12c de la base de données Oracle ? Alors découvrez nos prochaines dates de formation sur Paris et en région |
2 réflexions sur “Oracle Database 12c In-Memory: Configuration/Découverte de l’option”
super site que je connais depuis Arkzoyd … Jamais déçu ! 🙂
Merci bcp pour vos articles sur oracle.
C’est rare de trouver de la documentation écrite en français.
Cela m’aide dans mon travail.
Merci
Les commentaires sont fermés.