Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1245 connectés 

  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  [Tips] Utilisation de masques avec Oracle

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[Tips] Utilisation de masques avec Oracle

n°771340
Arjuna
Aircraft Ident.: F-MBSD
Posté le 21-06-2004 à 13:49:03  profilanswer
 

Au taff y'a un intervenant qui se la joue "I'm the great master of SQL" et malgré son très bon niveau, il a fini par me demander comment faire un truc, qui en effet est loin d'être évident.
 
Donc je vais pour l'expliquer ici, car c'est une optimisation courrant pour éviter les tables de jointures quand le nombre de lignes de jointures est fixe.
 
On s'en sert généralement pour apposer un flag (true/false) a une information dépendant d'une liste finie d'éléments.
Par exemple dans le cas d'une flag "afficher" qui dépendrait d'un pays. La liste des pays est une donnée qui évolue très peut, et peut donc être appliquée à ce système.
Un calendier des jours fériés aussi.
 
Le but du jeu, c'est de stocker dans une colonne unique toutes ces informations à l'aide d'un masque binaire. Ainsi, avec un INT(32) on peut stocker 32 flags, ce qui économie 32 lignes dans une table de jointure.
 
Je vais prendre l'exemple d'un calendrier.
 
Mettons une table calendrier.
 

NOMCAL    varchar(30)
ANNEE     smallint
JANVIER   int
FEVRIER   int
MARS      int
AVRIL     int
MAI       int
JUIN      int
JUILLET   int
AOUT      int
SEPTEMBRE int
OCTOBRE   int
NOVEMBRE  int
DECEMBRE  int


 
Chaque colonne portant le nom d'un mois contient une série de bits contenant au jour. Donc un nombre sur 32 bits (4 octets) suffit à stocker les informations pour un mois entier.
Chaque jour férié aura un 0 et les jours ouvrables aurons un 1
 
Par exemple, janvier de cette annee :
 
1000001100000110000011000001101
Notez qu'il faut lire de droite à gauche puisqu'il s'agit d'une représentation binaire.
 
Ce qui donne une fois converti en INT :
1099105805
 
Pour retrouver le status d'un jour dans le mois, il suffit de lire le bit à l'index numjour-1, ce qui se fait avec cette formule :
 
masque ou 2^(numjour-1)
 
Avec Oracle ce sera donc :
 

mod(trunc(lemois / power(2, to_char(ladate, 'DD') - 1), 0), 2)


 
Maintenant, on n'a plus qu'à trouver le bon mois dans la table en fonction de la date. On utilise simplement un décode :
 
 

mod(trunc(decode(to_char(sysdate, 'MM'), '01', janvier, '02', fevrier, '03', mars, '04', avril, '05', mai, '06', juin, '07', juillet, '08', aout, '09', septembre, '10', octobre, '11', novembre, '12', decembre) / power(2, to_char(ladate, 'DD') - 1), 0), 2)


 
Enfin, on fait notre select :
 

select mod(trunc(decode(to_char(ladate, 'MM'), '01', janvier, '02', fevrier, '03', mars, '04', avril, '05', mai, '06', juin, '07', juillet, '08', aout, '09', septembre, '10', octobre, '11', novembre, '12', decembre) / power(2, to_char(ladate, 'DD') - 1), 0), 2)
from calendrier
where nomcal = 'FERIE'
and annee = to_char(ladate, 'YYYY')


 
Vous n'avez plus qu'à remplacer "ladate" par votre date.
Cette requête retournera 1 pour un jour férié et 0 pour un jour ouvré.
 
Pour remplir la table, il suffit d'utiliser cette même technique.
 
Niveau performances, ça n'en a pas l'air, mais c'est extrêment efficace.
En effet, dans cette exmeple, déjà, on joue avec des nombres 32 bits, donc traîtés en un seul cycle avec n'importe quel système.
Ensuite, on travaille avec des puissances de 2. Tout programme correctement écrit va savoir faire des décallages plutôt que des puissances / divisions effectives.
Et surtout, en temps normal, pour stocker une année complète, on aurais certainement fait :
-> Soit 365 lignes avec identifiant + donnees (généralement, au moins 5 octets)
-> Soit x lignes avec identifiant + donnees (si on ne stocke que les jours remarquables) (généralement, au moins 5 octets)
 
Dans le premier cas, on traîte rapidement un nombre important de données pour rien.
Dans le second, on traîte un peu moins de données, mais avec une jointure externe si on ne veux pas perdre les infos des jours non remarquables.
 
Avec le système que j'ai indiqué, on n'a qu'une seule ligne de 48 octets d'info, donc beaucoup moins, et les traîtements, tout aussi rapides.
 
En revanche, ce système a une grosse limitation : il est extrêment difficile de travailler avec des intervalles de dates, et a ce moment les performances pourraient devenir très faibles.
 
Ceci-dit, si on traîte les infos en dehors de la base (via programme) on obtiendra toujours de très bonnes perfs, a condition de traîter une seule ligne à la fois.
 
Comme j'ai dit, ce système est donc très limité de ce point de vue. Pour le reste, il est réputé meilleur, et compatible avec mon nombre de classes existantes traîtant déjà les informations de cette façon en mémoire (ce système offre un gain fantastique d'occupation mémoire et de cycles processeurs pour la relecture, et est donc courrament utilisé dans nombre de programmes)

mood
Publicité
Posté le 21-06-2004 à 13:49:03  profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  [Tips] Utilisation de masques avec Oracle

 

Sujets relatifs
Conseil pour l'utilisation du xml dans une appliBesoin de conseil concernant l'utilisation du XML, ben alors?
[Oracle] Requête très lente. Que faire ?utiliser OCI avec oracle 7
executer une procedure oracle dans la consoleCréation hierarchique XML via ADO & Arbre Oracle SQL
Oracle : Arbre SQLQuery sur DB Oracle via PHP : charge CPU énorme !
[Résolu] Utilisation de getch et getkey[Visual Basic] utilisation d'un dll C++ && fuite memoire
Plus de sujets relatifs à : [Tips] Utilisation de masques avec Oracle


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR