Les tables externes

Introduction

L’idée saugrenue de jouer avec les tables externes[1] m’est venue de la volonté de pouvoir corréler[2] les statistiques systèmes et les statistiques provenant d’Oracle.
Ce que je souhaitais obtenir avec ce système était l’accès complet à l’historique de sar au travers d’un langage de manipulation de données, le SQL. Enfin un script shell viendra compléter l’arsenal et rendra opérant ce système. Attention, ce script sera appelé à chaque accès de la table.
Pour des raisons de sécurité, je vous incite fortement à lire la documentation oracle sur les risques[3] liés à l’utilisation de la clause PREPROCESSOR.

Ingrédients

  • Une tasse de café
  • Un siège
  • Un système *nix où sar est actif
  • Une base de données Oracle
  • Les droits DBA
  • Un copier/coller fonctionnel

Préparation

Pour que ce système ne soit pas trop intrusif, j’ai fait le choix de créer un utilisateur dédié: systat. La suppression n’en sera que plus aisée.
Le mot de passe ne sera probablement pas en accord avec votre politique de sécurité, corrigez l’assaisonnement à votre gout.

CREATE USER systat
IDENTIFIED BY systat
ACCOUNT LOCK;

Pour que mon petit bonhomme puisse faire quelque chose, je lui donne des droits, juste ce qu’il faut, sur des dossiers créés ci-dessous.
Le premier dossier hébergera le(s) script(s), le second, les fichiers de log.

CREATE DIRECTORY dbabin
AS '/home/oracle/dba/bin';
CREATE DIRECTORY dbatmp
AS '/home/oracle/dba/tmp';

Voici maintenant les droits spécifiques à chaque dossier.

GRANT READ, EXECUTE
ON DIRECTORY dbabin
TO systat;
GRANT READ, WRITE
ON DIRECTORY dbatmp
TO systat;

Pour ne pas rendre indigeste cet article, je n’ai gardé que la table du load average.
Vous pourrez créer une table pour les autres métriques selon vos besoins, le principe reste le même.

CREATE TABLE systat.ldavg (
  host       varchar2(255),
  last_snap  number,
  snap_time  timestamp,
  runq_sz    number,
  plist_sz   number,
  ldavg_1    number(6,2),
  ldavg_5    number(6,2),
  ldavg_15   number(6,2)
) ORGANIZATION EXTERNAL (
  TYPE ORACLE_LOADER
  DEFAULT DIRECTORY dbabin
  ACCESS PARAMETERS (
    RECORDS DELIMITED BY NEWLINE
    NOBADFILE
    NODISCARDFILE
    LOGFILE dbatmp:'loadavg.log'
    PREPROCESSOR dbabin:'loadavg'
    FIELDS TERMINATED BY ";" LRTRIM
    (
      host,
      last_snap  unsigned integer external (4),
      snap_time  char date_format timestamp mask 'yyyy-mm-dd hh24:mi:ss',
      runq_sz    unsigned integer external (4),
      plist_sz   unsigned integer external (4),
      ldavg_1    decimal external,
      ldavg_5    decimal external,
      ldavg_15   decimal external
    )
  )
  LOCATION(dbabin:'loadavg')
)
REJECT LIMIT UNLIMITED
/

Et enfin, parce que je n’aime pas les choses compliquées, un synonyme est le bienvenu.

CREATE SYNONYM loadavg
FOR systat.ldavg;

Voilà pour la partie SQL, il me reste à présenter le script shell /home/oracle/dba/bin/loadavg

#!/bin/env bash
# MAIN
{
  unalias -a
  declare -x PATH=/bin:/usr/bin
  test -d /var/log/sa &&
    ls -tr /var/log/sa/sa?? | xargs -rI@ sadf -td @ -- -q | sed 's/,/\./g'
}

Je positionne le bit d’exécution sur le script avec la commande chmod +x /home/oracle/dba/bin/loadavg et maintenant je peux m’amuser avec mon nouveau jouet.
[1]: Managing External Tables
[2]: correlation does not imply causation
[3]: Guidelines for Securing the ORACLE_LOADER Access Driver