Volume I
André Gamache 2005
Fascicule 3
Architectures, modèles et langages de données
Hypercube
Ingénierie des bases de données
OLAP
c,d
Langage SQL, indexation et vue relationnelle
Architectures, Modèles et Langages de Données
Volume 1
Fascicule 11- Introduction 1
2- Architecture fonctionnelle du SGBD 20
3- Modèle conceptuel des données 79
- Index
Fascicule 2
4- Modèle relationnel : théorie et contraintes d’intégrité 1
5- Algèbre relationnelle 57
6- Transposition du MCD au MRD 137
- Index
Volume 2
Fascicule 37- Langage de données SQL 1
8- Indexation, vue relationnelle et base réactive 123
- Index
Fascicule 4
9- Langage de programmation et SQL 1
10- Théorie de la normalisation relationnelle : les formes normales FN1 à FN5 45
11- Optimisation des requêtes relationnelles 117
Annexes : A- SQLoader
B- Projet ALU-Nord : Script de chargement des données - Index
Chapitre 7
Langage de données SQL DDL, DML et les recherches
Dans les sections précédentes, les éléments au langage SQL ont été présentés afin d’illustrer les formulations équivalentes aux opérateurs algébriques. La facette DDL du langage a aussi été présentée avec plusieurs détails afin de pouvoir créer et formuler correctement les contraintes des tables. Dans ce chapitre, nous approfondirons les clauses SQL‐DDL en examinant quelques paramètres qui ont trait aux structures physiques et nous poursuivrons l’étude du langage de requête SQL, en accentuant davantage les diverses fonctions disponibles dans ce langage sans égard à leur implémentation dans un SGBD particulier. Encore ici, de nombreux exemples sont formulés avec le SQL implémenté par Oracle, lequel correspond à peu près au niveau 2 de la norme SQL‐92. Nous étudierons en détails l’implémentation Oracle de certaines notions qui sont particulières à ce logiciel SGBD. Cependant, notre étude débordera les limites imposées par Oracle pour discuter aussi de plusieurs autres notions et implémentations propres à d’autres SGBD.
7.1 Langage SQL et l’exploitation de la base de données
Le langage de données SQL créé dans les années 70 découle des travaux d’une équipe de chercheurs de la société IBM qui travaillait à la mise au point des langages de données SQUARE et SEQUEL dans le cadre du développement du système R, précurseur de plusieurs SGBD relationnels, notamment du système SGBD DB2. Lʹacronyme SQL signifie Structured Query Language. C’est un langage à mots clés réservés. Il est non procédural dans sa formulation, masquant assez bien le caractère algébrique des expressions syntaxe relativement simple, mais affiche une facette de langage naturel, soit l’anglais élémentaire. Le langage SQL a fait lʹobjet de plusieurs efforts de normalisation qui ont débuté de façon sérieuse en 1989 et qui se poursuivent toujours. Toute norme SQL publiée peut être implantée à divers niveaux, selon les choix faits par le développeur du SGBD. Trois niveaux sont possibles : minimal (1), intermédiaire (2) et complet (3). Ce dernier niveau doit respecter intégralement la norme SQL. Il y a plusieurs normes SQL, chacune enrichissant la version précédente : SQL‐89, SQL‐92 et SQL‐93.
Lʹimplantation de SQL par la société Oracle est fortement similaire à la norme ISO‐SQL‐
92 de niveau 2. Il en est de même aussi pour le système WATCOM SQL. Le langage SQL comporte trois facettes fortement intégrées peu importe le SGBD relationnel :
a) DDL (Data Definition Language), pour la définition des tables, des contraintes diverses et des vues relationnelles stockées dans le dictionnaire du SGBD.
b) DML, (Data Manipulation Language) pour la manipulation des tables et plus précisément les manipulations des tuples de relations.
c) DCL, (Data Control Language) pour gérer la définition physique des accès (index), la spécification des fichiers physiques et la validation des opérations exécutées dans un contexte multiposte.
SQL et les autres langages L3G
Le langage SQL (Oracle) est utilisé de façon autonome et interactive (au moyen du module SQL*Plus interactif). Il est aussi utilisé dans les blocs de PL/SQL (SQL intégré à un langage procédural interactif de Oracle) et dans les applications mises au point avec les L3G grâce aux API (interfaces de programmation pour les applications). Finalement, le SQL dynamique permet la formulation de requêtes dont la spécification complète ne sera connue qu’au moment de lʹexécution.
SQL*Plus (rappel sur cette application)
Les clauses du langage SQL de Oracle sont prises en charge par le module utilitaire SQL*Plus qui les réceptionne et les transmet à lʹinterpréteur de SQL qui est un service intégré du SGBD. Après le calcul de la réponse, le module SQL*Plus reçoit les tuples et les affiche selon des paramètres qui peuvent être fixés par lʹutilisateur au moyen de directives particulières. Il y a dʹautres modes dʹinteraction avec le SGBD, notamment par lʹentremise des applications développées en langage de troisième génération (L3G) et utilisant lʹinterface API appelée OCI chez Oracle.
Le module SQL*Plus est donc lʹintermédiaire incontournable lorsquʹun développeur veut exécuter une clause SQL en mode interactif. Le texte de la dernière clause est placé dans un tampon prédéfini et nommé par un nom interne suffixé par SQL. Cet espace peut contenir seulement une clause SQL, excluant les directives ayant trait au formatage, à lʹenvironnement et à lʹaffichage de la réponse par le module SQL*Plus. Pour contourner cette restriction, il est possible de définir un autre tampon courant par la directive SET BUFFER dont la durée est celle de la session de travail.
Figure 7.1 Utilitaire SQLPlus et script d’exécution
L’application utilitaire SQLPlus est incontournable pour la mise au point et l’exécution en ligne des clauses SQL. Cette utilitaire SQL*Plus comporte plusieurs directives :
SET BUFFER tampon1 -- un autre tampon courant est créé
SAVE C:\tampon1.sql --sauvegarde du tampon dans un fichier sur C SET BUFFER SQL -- retour au tampon par défaut de SQL*Plus
BD
serveur
Tampon SQL*Plus
Directives SQL*Plus
SGBD SQL*Plus
client
En outre, il est possible dʹenregistrer une trace complète de lʹaffichage avec la directive SPOOL :
SPOOL C:\trace.4juillet -- trace dans un fichier SPOOL ON -- début de la trace
SPOOL OFF -- pour terminer la trace; spool ON pour redémarrer
Un fichier de directives est très utile pour obtenir lʹenvironnement désiré et cela, dès le début dʹune session de travail. Voici un exemple dʹun tel fichier‐script qui est exécuté par la directive :
START :environbd3.sql)
Dans le fichier‐script, il faut insérer les commandes et/ou les directives suivantes : ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-YYYY', ALTER SESSION SET NLS_LANGUAGE_FORMAT = french COLUMN NOM FORMAT A25
.../*liste des formats requis pour l’affichage des colonnes*/
Le fichier est exécuté par START envirobd3.sql ou en le nommant init.sql ou login.sql, auquel cas il sera exécuté automatiquement avec le lancement du module SQL*Plus. Avant dʹaborder lʹétude du langage SQL, il est utile de survoler les différentes structures utilisées par la base de données afin de donner un sens physique aux paramètres des ordres SQL‐DDL. Ce survol est effectué en faisant référence au système Oracle dont lʹimplémentation du modèle relationnel et du langage SQL est reconnue comme étant de très bon niveau.
Les directives du module SQL*Plus sont résumées dans le tableau ci‐dessous.
APPEND* Ajout de texte à la fin de la ligne courante CHANGE Changement de texte dans une ligne CLEAR Supprimer le contenu du tampon courant
DEL Supprimer la ligne courante
DESCRIBE Liste du schéma d’une table
GET Lecture d’un fichier dans le tampon HOST <commande> Exécution d’une commande de l’OS (hôte) LIST Afficher le contenu du tampon courant
RUN *** Exécution de la commande ou du script rangé dans le tampon courant de l’application SQL*Plus
SAVE <fichier.sql> Écriture de tampon courant dans un fichier SPOOL <fichier.sql> Écriture de la trace de l’écran dans un fichier
* Les directives et les commandes peuvent être écrites indifféremment en majuscules ou minuscules.
Fonctions du dictionnaire de données
Le dictionnaire de données (DD) dʹun système relationnel est implanté comme une base de données du même type. Les structures de données utilisées sont les mêmes que celles utilisées pour stocker les données transactionnelles. Le dictionnaire contient les métadonnées nécessaires pour définir notamment les tables de la base de données. Le dictionnaire de données joue un rôle central dans le fonctionnement du SGBD relationnel. Son contenu est rangé dès le démarrage dans la RAM, accessible en ligne par le noyau du SGBD. Les tables du dictionnaire servent à diverses fonctions:
a) Stockage de la définition de la base de données : schéma, index, trigger, packages, fonctions, procédures, synonymes (alias) etc. Il est entièrement accessible à lʹadministrateur des données (DBA) et partiellement aux utilisateurs qui peuvent consulter les tables (et les autres objets) dont ils sont propriétaires.
b) Passerelle incontournable entre le noyau du SGBD et lʹinterpréteur du SQL pour effectuer lʹanalyse et le traitement des requêtes SQL. Le dictionnaire est essentiel à lʹappariement (binding) dynamique avec les applications L3G, notamment en ce qui concerne la compatibilité entre le type interne dʹune donnée et le type externe disponible dans le langage de programmation hôte.
c) Documentation des divers objets de la base de données : tables, index , attributs, déclencheurs, packages.
d) Participation à la sécurité et à lʹintégrité de la base en stockant les droits dʹaccès des utilisateurs aux tables de base, aux vues et aux espaces de données.
e) Répartition des données au moyen des liens entre les bases qui sont spécifiées dans le dictionnaire et leur localisation géographique.
Introduction à lʹorganisation des espaces physiques et logiques de la base de données Oracle
La base de données Oracle est définie comme un ensemble de tables (relations) appartenant au compte créateur des tables qui a généralement la propriété du DBA.
L’unicité du nom dʹune table est assurée par l’adjonction automatique du préfixe formé avec le numéro de compte de lʹutilisateur propriétaire. La répartition des données sur plusieurs serveurs est prise en considération par les métadonnées du dictionnaire sur la localisation, notamment les liens de placement. L’ensemble des définitions de table correspond au schéma de la base de données qui est exprimé en SQL‐DDL.
7.2 Objets Oracle
Un objet ou plus précisément une entité de la base de données Oracle, est la notion utilisée pour représenter les éléments suivants : le schéma de relation, lʹextension d’une
relation (table), les déclencheurs (trigger), la fonction, la procédure interne, lʹespace de données, lʹindex, la vue, le trigger et le package. Tous ces objets sont rangés dans les tables du dictionnaire du SGBD, sauf l’extension de la relation qui est stockée dans un espace de table (tablespace). L’accès à chacun des objets est contrôlé par des droits qui sont accordés et, au besoin, révoqués par le DBA.
Figure 7.2 Espace de stockage Oracle
Une relation du MRD est implémentée par une structure de table définie comme une liste de pages physiques appartenant à un tablespace défini et associé à un ou plusieurs fichiers gérés par le système d,exploitation du serveur. Chaque table ne contient généralement que des tuples de même schéma. Il y a une exception avec les tables stockées dans un cluster. Un extent est l’unité d’allocation de l’espace et les extents d’une même table forment un segment.
Structure physique de table : pages enchaînées Figure 7.2a
Chaque table dʹun schéma appartient au compte (Oracle) qui l’a créée. Par défaut, le nom complet dʹune table est formé du nom du compte suffixé par le nom de la table:
compteChef. Tous les droits d’accès sur une table sont acquis automatiquement par le propriétaire de la table qui peut cependant les partager en propageant aux autres les droits dʹaccès appropriés (commande GRANT). Une table Oracle est accessible par diverses interfaces relationnelles, notamment via le module SQL*Plus, le langage procédural PL/SQL et lʹinterface de programmation des applications (API) utilisant un langage de troisième génération.
Compte5.r2
Compte6.r2
Dictionnaire de données, schémas, procédures, … Compte4.r1
SGBD Instance1 BD
Piage i
Page i+1
extent1 extent2
Organisation logique des espaces de stockage pour les données et les index
La structure de l’espace physique d’une base de données est définie par le DDL au moyen de plusieurs paramètres qui spécifient l’allocation initiale de l’espace pour une table, à même celui du tablespace auquel la table sera associée. Les données du système Oracle sont stockées via des espaces logiques, appelés espaces de table (tablespaces) (TS), chacun composé de segments, eux‐mêmes composés de lots homogènes et contigus d’octets appelés extents. Ces espaces sont utilisés pour stocker notamment les tables, les index, les clusters et les données des segments de recouvrement transactionnel (rollback).
Figure 7.2b
Une extent est défini comme une unité dʹallocation de lʹespace physique. Les extents dʹun segment peuvent être dispersés et chaînés. Sur le plan de l’espace physique, un extent est formé de pages contiguës (blocs Oracle). Finalement, une page est constituée de plusieurs blocs du système d’exploitation hôte, blocs dont la taille est fixée lors de la création de la base de données. Lʹespace physique dʹune base de données peut être augmenté par le DBA, par lʹajout, en tout temps, dʹun ou de plusieurs fichiers dans un espace de table particulier.
Page Oracle
Une page Oracle est une suite de blocs physiques constitués dʹoctets contigus (1 K à 16 K). La taille d’une page est fixée à la création de la base de données par le paramètre DB_BLOCK_SIZE initialisé dans le fichier INIT.ORA. Une page contient normalement des tuples dont la structure est homogène, i.e. appartenant à une seule table, sauf pour les pages de cluster. Ces pages ont une structure particulière permettant d’y ranger des tuples en provenance d’au moins tables différentes.
Espace de table (tablespace)
Toute entité ou tout objet dans une base de données relationnelle est rangée dans une table qui est elle‐même placée dans un espace de table particulier appelé tablespace . Cet espace sur disque est associé à un fichier physique. Le compte Oracle SYS est, à la création de la base de données, le propriétaire initial des objets du dictionnaire et de
Espace de table AB
Segment 1 Segment 2
Extent 1 Extent 2 Extent 3 Extent 4 pages
Fichier B A
Fichier B
certaines autres tables utilisées en cours dʹexploitation pour stocker les métadonnées traitant de la performance et de lʹexploitation des tables.
Le premier compte DBA créé lors de lʹinstallation du SGBD est nommé SYSTEM.
L’espace de table SYSTEM est aussi créé à lʹinstallation et il appartient au compte de même nom. Les divers objets créés y sont placés par défaut, y compris ceux des utilisateurs, sauf si lʹutilisateur propriétaire de lʹobjet requiert de le faire autrement. Une meilleure performance est atteinte si les objets dʹindex et de tables des utilisateurs sont placés dans autant de TS (tablespace) distincts créés par le DBA. C’est le principe de base de l’architecture optimale appelée OFA (Optimal Flexible Architecture) et suggérée pour Oracle 1.
Figure 7.3
Structure générale de page
Une page a une taille fixée au lancement de lʹinstance et cela, par lʹentremise du paramètre de système BLOCK_SIZE. Sa taille peut varier jusquʹà 16 Ko. Chaque page a une zone de gestion de son espace qui est appelée répertoire des tuples ou de lignes.
L’espace d’une page est assortie d’une contrainte qui est la suivante :
PCTFREE + PCTUSED < 100
Dans ce répertoire, on trouve une entrée où est inscrit un déplacement (offset) dans la page qui est en quelque sorte un pointeur sur le début du tuple. Lors dʹune réorganisation de la page, les tuples sont déplacés vers le bas afin de récupérer lʹespace libre. Seuls les déplacements sont modifiés, tandis que le rid ( soit le TID pour Ingres et le ROWID pour Oracle) demeure constant, évitant ainsi de faire la mise à jour des index
1..*
1..*
BD
Schémas Comptes
FichierPhysique EspaceDeTab
Extent Page
Segment Table 1..*
1..1
1..1 1..1
1..1
1..1
1..* 1..1
1..1 1..*
1..1 1..1 1..1 1..*
1..*
1..*
1..*
1..* 1..* 1..1
Figure 7.4
Lʹen‐tête de la page contient des données pour la gestion transactionnelle, notamment les adresses logiques (rid) des tuples verrouillés avec le numéro de la transaction propriétaire du verrou. Lors dʹune relecture de la page, le système vérifie si une transaction inscrite dans lʹen‐tête (qui a donc lu un tuple) est encore active et, dans le cas affirmatif, considère que le tuple est toujours verrouillé. Sinon, le verrou est périmé et le tuple est considéré disponible pour les autres transactions. L’adresse logique d’un tuple nommé rid ou rowid (row identifier) est souvent formée de la façon suivante :
rid ::= noFichier:noPage:noEntreedansRepertoire Page Oracle
Chaque page ou bloc Oracle est composé de blocs physiques d’octets contigus et est l’espace utilisé pour ranger les tuples d’une même table. La structure de la page comprend au moins trois parties : un en‐tête, une zone primaire pour ranger les tuples (PCTUSED) et une zone de débordement (PCTFREE) pour ranger les tuples dont la taille a augmenté suite à une mise à jour. Par défaut, le système Oracle fixe la zone primaire à 40% de la taille de la page et la zone de débordement à 10 %. Dans les cas où il y a peu de mises à jour et beaucoup d’ajouts, les valeurs par défaut (10/40) pour les paramètres PCTFREE et PCTUSED ne sont pas toujours adaptées aux besoins d’un tel environnement d’exploitation. Il faut les ajuster par exemple à 5/80 lorsquʹil y a peu de mises à jour.
Le rôle du paramètre PCTFREE est de réduire le chaînage des parties de tuples dʹune page à lʹautre. Cette fragmentation dʹun tuple devrait se faire pour réaliser une mise à jour qui exige un espace plus grand non disponible à lʹadresse actuelle. À la création dʹune page, le paramètre PCTFREE indique le pourcentage de la page à garder en réserve pour y reloger les tuples mis à jour. Le paramètre PCTUSED permet de
En‐tête de page
Zone d’élargissement des tuples
Zone de tuples
Répertoire des tuples
INITRANS : espace pour la gestion des accès à la page
MAXTRANS : nombre maximum de transactions en accès simultané.
PCTFREE : % de l’espace de page réservé à l’élargissement des tuples lors de la mise à jour.
PCTUSED : % de la page réservé aux données et en dessous duquel la
minimiser les lectures et les écritures sur le disque en indiquant au serveur le pourcentage de lʹespace occupé dʹune page, qui doit être atteint avant que la page soit désignée à nouveau comme une page insérable. En effet, les insertions se poursuivent dans une page tant et aussi longtemps que le pourcentage du PCTFREE est respecté. À ce moment, la page est marquée non insérable et supprimée de la liste des pages disponibles (free list). Des insertions de tuples seront faites à nouveau dans cette page, lorsque les suppressions ramèneront le pourcentage dʹoccupation de lʹespace sous la barre du paramètre PCTUSED.
Les tuples des tables et des index peuvent cohabiter ou non dans le même espace de table tout en étant rangés obligatoirement dans des segments différents et donc dans des extensions différentes. Dans une extension donnée, il n’y a donc que des pages de données de tables ou d’index et non les deux. Dans les deux cas, les paramètres PCTFREE et PCTUSED sont utilisés pour la gestion de lʹespace de la page. Avec lʹindex, le paramètre PCTFREE doit être assez grand pour une table indexée, surtout lorsque le taux de mise à jour est élevé. En effet, tout ajout de tuples dans une table indexée entraîne une mise à jour de lʹindex, donc une augmentation de la taille des entrées, notamment pour les index sur les attributs de type chaîne. Ceci entraîne rapidement un débordement dans la zone libre. Pour éviter le chaînage des tuples qui ralentit la lecture, il faut prévoir dans chaque page un espace libre un peu plus grand pour les pages destinées à stocker les index.
Page insérable
Une page a le statut dʹinsérable si le SGBD est autorisé à y ajouter encore des tuples, sinon elle a le statut de page non disponible. Lorsque l’occupation dʹune page est telle que lʹespace restant correspond à lʹespace réservé par le PCTFREE, la page est enlevée de la liste des pages insérables (free list). Elle ne peut plus recevoir de nouveaux tuples, mais on peut toujours mettre à jour les tuples présents en utilisant la zone libre ou de débordement. Par contre, lorsque les suppressions et les modifications (changement de la valeur d’un attribut qui fait passer sa taille de 450 à 40 caractères ou la mise à jour d’un attribut null) ramènent l’espace occupé en dessous de la valeur PCTUSED pour cette page, celle‐ci est réinscrite dans la liste des pages insérables et de nouveaux tuples peuvent y être ajoutés. Lorsquʹun tuple est ajouté dans une page, il est possible que lʹespace occupé dépasse le PCTUSED, et cela, tant que la limite du PCTFREE est toujours respectée. Cette situation peut se produire si PCTUSED + PCTFREE < 100. Lorsque les paramètres PCTUSED et PCTFREE ne sont pas adaptés à lʹenvironnement d’exploitation de la base de données, cela conduit à des échanges de pages supplémentaires inutiles entre le disque et la ZMP (Zone de Mémoire Partagée). Pour une exploitation avec un faible taux de réorganisation et de mise à jour, le facteur PCTUSED devrait être de l’ordre de 80 et le PCTFREE de 10.
Migration des tuples
Lorsquʹun tuple est modifié et quʹil ne peut pas être replacé dans son espace dʹorigine, le système cherche à le ranger en entier dans lʹespace du PCTFREE (zone de débordement) et une adresse de suivi est placée dans lʹespace dʹorigine afin de garder lʹadressage initial fonctionnel pour les index.
Figure 7.5
Ainsi, les entrées dʹindex sur cette table pointent toujours au même rid (ou rowid) et dans la même page et cela, même si le tuple pointé a été déplacé. Le traitement des index incorpore celui du suivi dʹun tuple au fil de ses adresses de déplacement. Cʹest la migration des tuples. Pour lire un tel tuple, le système nʹa pas à effectuer un accès disque supplémentaire puisquʹil se trouve dans lʹespace de débordement de la même page.
Après lʹinsertion du tuple dans lʹespace PCTFREE (débordement), lʹespace dʹorigine nʹest occupé que par une adresse de suivi et le reste de cet espace pourra être éventuellement récupéré pour y placer les données dʹun autre tuple. Si le tuple modifié ne peut pas être rangé dans lʹespace du PCTFREE, il est déplacé entièrement dans une nouvelle page insérable et la nouvelle adresse est aussi rangée dans son emplacement initial afin dʹen permettre le suivi à partir des index existants, qui pointent toujours sur lʹemplacement dʹorigine. Lʹinconvénient de cette gestion est que cela oblige à faire deux lectures au lieu dʹune seule pour accéder au tuple recherché.
Fragmentation des grands tuples et chaînage
Une deuxième solution à la gestion des tuples plus encombrants (par exemple les tuples avec un BLOB) consiste à les diviser et à chaîner leurs parties. Lorsquʹun tuple modifié ne peut pas être rangé ni dans sa page dʹorigine ni dans une autre page de la base de données, le serveur divise le tuple en parties chaînées et chacune sera rangée dans une page ayant lʹespace suffisant.
Figure 7.6
12 :89
Tuple modifié et placé dans la zone de débordement
Place initiale du tuple de rid = 12 :34
tuple rid : 23:12 PCTFREE
PCTUSED 56:77
123:45 en‐tête
Cʹest le chaînage dʹun tuple qui nʹintervient que lorsque la migration est impossible. Le chaînage est aussi pénalisant parce quʹil faut faire plusieurs lectures sur disque pour retrouver la première partie et autant de lectures supplémentaires pour lire les autres.
Placement des données : regroupement
La notion de regroupement des tuples (dans une structure de cluster) concerne généralement plusieurs tables qui partagent les pages dʹun même segment spécial appelé cluster.
Figure 7.6a
Ces tuples cohabitent parce qu’ils ont en commun des valeurs d’attributs de regroupement (key cluster attributes) et quʹils sont souvent utilisés par les applications dans une opération de jointure. Étant logés dans les mêmes pages, la vérification de la condition de jointure sera faite plus rapidement parce quʹils seront accessibles sans nécessiter d’échanges de pages supplémentaires entre le noyau du SGBD et le disque des données. On peut concevoir la structure logique dʹun cluster comme ayant un répertoire dʹen‐tête construit avec les valeurs partagées par deux tuples de tables différentes.
Chaque entrée du répertoire pointe sur les deux tuples au moyen de deux rid. Un cluster peut aussi être défini pour ne loger que les tuples dʹune même table, en les regroupant selon la valeur dʹun attribut particulier.
Rappel de quelques notions sur les arbres utilisés par les index
Les index utilisés par Oracle2 ont généralement une structure en B*‐arbre. Ils sont rangés dans des tables, elles‐mêmes placées dans un segment dédié à un index et éventuellement dans un espace de données (tablespace) spécialisé, créé par le DBA. Cette structure est du type index hiérarchique : les feuilles pointent sur les adresses rids (ou encore ROWID) des tuples indexés par un attribut dont les valeurs indexées sont regroupées et ordonnées dans une cellule terminale (feuille). Chaque cellule terminale est indexée au niveau supérieur qui contient un pointeur de plus que le nombre de valeurs dans la cellule. Par exemple, la recherche du tuple indexé par la valeur 76 débute à la racine, par l’examen de la première et de la dernière entrée pour déterminer le sous‐
arbre à explorer. Le premier examen indique qu’il faut explorer le sous‐arbre milieu et la 45 ::::23 :34
(45) ::::23 :67
45, ‘jacques’, 75
75, ‘patricia’, 45 Valeur de clé du cluster =
En‐tête du cluster
procédure se poursuit ainsi jusqu’à l’atteinte du dernier niveau. Une telle structure arborescente est gardée équilibrée par une procédure de mise à jour et la longueur moyenne du chemin d’accès à n’importe quel tuple est constante. Pour 106 tuples, il faut environ cinq accès pour retrouver un tuple. Dans le pire des cas, cinq lectures sur disque sont nécessaires pour obtenir autant de pages.
Chaque clé primaire spécifiée dans un schéma de table génère soit un index interne (du type Système), soit une procédure interne pour vérifier la contrainte de clé. Toutefois, lʹindex système peut être désactivé (disable), auquel cas l’index nʹest pas utilisé pour renforcer la contrainte dʹentité. La contrainte de NULL continue de sʹappliquer aux attributs primaires. La création d’un index avec un attribut se fait par une commande SQL‐DCL et suppose un tri des valeurs de la clé. Lʹopération sera effectuée dans un espace de mémoire temporaire géré par le SGBD. Un index créé par le DBA peut être supprimé à volonté et refait plus tard. Dans certains cas, le DBA peut accorder à un utilisateur le droit de créer un index. Si une telle structure est intéressante pour la recherche, elle gêne souvent la mise à jour. En effet, l’ajout d’un nouveau tuple indexé par la valeur 9 implique une insertion de la clé dʹindexation dans la cellule référencée par le pointeur droit de la clé 3 (voir Figure 7.8). Or, cette cellule étant déjà saturée, la cellule ciblée sera divisée et la valeur médiane insérée au niveau supérieur par la même procédure. Ces opérations exigent des accès aux disques qui ralentissent les opérations dʹaccès à la base de données. Le maintien de l’équilibre de l’arbre est toutefois assuré et réparti entre les différentes opérations sur la base de données.
7.3 B‐arbre
Le B‐arbre dʹorigine est construit à partir de la racine et il est géré pour demeurer toujours équilibré, i.e. avec une hauteur à peu près constante (Figure 7.7).
Figure 7.7
21 81
tuple
3 12 35 52 85 91
1 2 13 19 37 39
87 90
95 99
23 26
5 10 55 62
84 82
Pointeur sur clés supérieures à celles de gauche et inférieures à celles de droite.
Pointeur sur tuple
L’absence de la flèche indique l’absence de pointeur.
Les cellules feuilles sont aussi reliées par un chaînage latéral afin de faciliter le balayage séquentiel partiel ou complet des tuples d’une table.
Les caractéristiques de cette structure sont les suivantes :
Une cellule contient p pointeurs aux sous‐arbres toujours équilibrés et un maximum de (p‐1) clés. Lʹarbre est dit dʹordre p.
Le pointeur à la gauche dʹune valeur de clé référence un sous‐arbre dont les clés sont inférieures ou égales à la clé du nœud; le pointeur à la droite fait référence un sous‐arbre dont les clés sont supérieures. Le pointeur sur un tuple est constitué du rid, cʹest‐à‐dire lʹadresse de la page. Ce pointeur est inséré dans chaque nœud et non seulement dans les feuilles.
Avec l’arbre d’ordre 3 de la Figure 7.7 ( 3 pointeurs et 2 valeurs de clé), la clé 9 est ajoutée pour fournir l’arbre suivant représenté à la figure 7.8. Le rééquilibrage est généralement immédiat, ou légèrement différé, cʹest‐à‐dire quʹil est fait pratiquement à chaque ajout ou modification dans le B‐arbre. En insertion, le tuple est stocké dans une page et sa clé insérée dans la cellule appropriée de lʹindex avec les divisions et les migrations des tuples quʹimposent les règles dʹéquilibre. La principale caractéristique de cet arbre est que les nœuds internes contiennent des pointeurs aux tuples et que les clés ne sont pas redondantes dans les feuilles.
Procédure algorithmique dʹinsertion
La clé dʹun tuple est insérée en trouvant la cellule où elle devrait être normalement placée. Sʹil y a lieu, la division de la cellule est faite et la clé à la droite de la médiane est déplacée au le niveau supérieur en utilisant la procédure dʹinsertion. Lʹopération est récursive.
Procédure de suppression
La suppression dʹun tuple dans une cellule conserve cette dernière intacte si le nombre de pointeurs résiduel est supérieur à p/2, où p est lʹordre de lʹarbre.
Figure 7.8
Calcul de la hauteur dʹun arbre dʹordre 3 (avec p = 3 pointeurs par cellule) La hauteur dʹun B‐arbre peut être estimée par un simple raisonnement inductif : niveau h=1: 1 cellule, 3 pointeurs et 2 clés : 30 p0 cellule et p0 x (p‐1) clés niveau h=2: 3 cellules, 9 pointeurs et 6 clés : 31 p1 cellules et p1 x (p‐1) clés niveau h=3 9 cellules, 27 pointeurs et 18 clés : 32 p2 cellules et p2 x (p‐1) clés donc au niveau h : p(h‐1) (p‐1) >= n (où n est le nombre de tuples)
(h‐1)log p + log(p‐1) >= log n
h>= 1 + (log n ‐ log(p‐1)) avec log dans la base p (soit l’ordre de l’arbre).
Donc le nombre moyen de pages lues dans un accès est environ logp n (dans la base p).
Pour un arbre d’ordre plus élevé, par exemple 50, les gains en terme d’accès sont encore plus significatifs : avec n = 500 000 tuples et p = 50 on a h ≈ 4. Soit quatre lectures nécessaires pour atteindre la feuille recherchée dans un B‐arbre. Dans le cas courant où la cellule est une page, lʹadresse se réfère à celle‐ci, la recherche dʹune clé en mémoire se fait très rapidement. En effet, la taille d’une page (8Ko) pour la cellule confère un ordre relativement élevé à l’arbre pour ainsi en diminuer sensiblement la hauteur à une constante généralement inférieure à 8. La base p du logarithme joue un rôle critique. En effet, plus p est grand, plus la valeur du log dans la base p est petite.
Avantages de la structure en B‐arbre
Le B‐arbre offre plusieurs avantages lorsquʹil est utilisé comme index :
‐ Le parcours moyen pour trouver un tuple est inférieur à la hauteur de lʹarbre.
12 21
tuple
3 10 35 52 85 91
1 2 13 19 37 39
87 90
95 99
23 26
5 9 55 62
82 84
81
tuple
‐ Il nʹy a pas de redondance des clés à la suite dʹune duplication dans les feuilles.
‐ La hauteur dʹun arbre pour indexer un nombre n de dossiers est la même quel que soit le chemin parcouru. Pour 2 millions de tuples, il est de lʹordre de 5 accès au disque.
Inconvénients du B‐arbre
Lʹajout et la suppression sont des opérations complexes en raison de la réorganisation des nœuds internes. Périodiquement, le DBA aura à supprimer lʹindex et à le recréer pour compacter les entrées. Les pointeurs aux tuples (8 octets) occupent lʹespace des cellules autrement occupé par des clés. Finalement, le parcours séquentiel des tuples est parfois difficile, voire impossible ou impraticable, en cas dʹabsence de chaînage latéral à tous les niveaux et en raison de la dispersion des pages qui exige plusieurs lectures sur le disque.
B*‐arbre
La structure du B*‐arbre est similaire à celle du B‐arbre, mais les clés des cellules intermédiaires sont aussi insérées dans les feuilles avec le pointeur aux tuples, i.e. aux données. Les nœuds intermédiaires ne pointent pas sur les tuples. Il y a donc une certaine réduction de la redondance, augmentant ainsi la densité des tuples dans les pages de données. Le parcours séquentiel des feuilles est possible au moyen du pointeur de chaînage latéral.
Variantes du B‐arbre
Deux variantes existent pour le B‐arbre :
‐ B+‐arbre : il correspond au B‐arbre classique avec des pointeurs aux tuples placés uniquement dans les feuilles et un remplissage des cellules qui ne dépasse pas la moitié de leur capacité.
‐ B*‐arbre : il est identique au B+‐arbre, mais avec la garantie dʹun remplissage de chaque cellule ne dépassant pas les deux tiers de sa capacité.
Le nombre de réorganisations des cellules peut devenir important, surtout à lʹapproche de la saturation des feuilles de lʹarbre. Dans la pratique, lorsque cet état est atteint au cours d’une mise à jour, les procédures de gestion de l’arbre amorcent immédiatement sa réorganisation en divisant le contenu de la cellule saturée en deux parties et en réallouant l’espace pour une ou plusieurs nouvelles cellules du B‐arbre. L’effort de rééquilibrage est consenti au fur et à mesure, par quanta répartis, afin d’éviter l’accaparement du noyau du SGBD aux temps d’une demande forte et durant lesquelles le travail de réajustement ralentirait les opérations dans la base de données.
Mécanisme de verrouillage des tuples
Normalement, un utilisateur du système Oracle exploitant directement les données par lʹentremise de SQL*Plus, soit par une application n’a pas à se soucier du verrouillage des données. La gestion des verrous est automatique et assumée par le SGBD du serveur. Un premier utilisateur qui accède à une table acquiert aussi un verrou dʹexclusivité TX (ou plus simplement X) sur chaque tuple modifié ou inséré et un verrou RX sur la table. Le verrou RX (RS en premier se transformant en RX) sur une table autorise la transaction à faire dʹautres actions sur les tuples de la table qui ne sont pas encore verrouillés par une
autre transaction. À la fin de la mise à jour marquée par un COMMIT transactionnel, les verrous sont automatiquement libérés par le moteur dʹOracle. Le système pose un verrou au niveau des tuples, sauf si une application le demande explicitement par la commande explicite LOCK TABLE. Le verrou contrôle alors toute la table. L’atomicité de chaque ordre SQL est assurée par le SGBD en ce sens quʹun ordre est complété ou en cas d’erreur, défait entièrement, et cela, sans intervention directe de lʹapplication.
7.4 Association des espaces de table avec les fichiers physiques
Les espaces de table nommés tablespaces (TS) sont associés à des fichiers physiques dʹun OS lors de leur création par le DBA. Les tables et les index sont créés et associés explicitement à un TS particulier par une commande particulière utilisée seulement par le DBA.
CREATE TABLESPACE ESPACE_USER3 --commande pour le DBA DATAFILE '/usr/users/fichier1.dbf' SIZE 25M
DEFAULT STORAGE INITIAL 50K NEXT 30K PCTINCREASE 0 MINEXTNENTS 1 MAXEXTENTS 100 ONLINE;
Une table peut être rangée explicitement dans ce tablespace déjà créé par la commande DDL suivante :
CREATE TABLE Usines(
no number(2) constraint cp_usines primary key, libelle varchar2(45),
ville varchar2(60),
capacite number, -- par défaut un entier de précision 32
classe char(1))
TABLESPACE ESPACE_USER3;
Lʹespace de table est nommé et son espace maximal spécifié dans une commande antérieure est de 50 Mo. Toutefois, lʹespace initial est de 50K et augmente, selon les besoins, par quanta de 30 Ko. Toute table stockée dans cet espace de table aura les caractéristiques de stockage par défaut. Normalement, lʹespace de table est créé par le DBA et non par les développeurs. La création d’une table se fit dans un espace prédéfini par le DBA et alloué au compte Oracle par défaut.
N.B. Si lʹespace de table nʹest pas fourni dans la commande CREATE TABLE ou prédéfini par défaut, les objets sont rangés dans lʹespace de table SYSTEM.
Les segments ROLLBACK et les INDEX sont aussi créés explicitement par le DBA : CREATE INDEX Usines_nom_idx On Usine(nom);
CREATE [PUBLIC] ROLLBACK SEGMENT segt25 TABLESPACE TS_table10;
La création d’un segment temporaire est effectuée automatiquement par le SGBD lors de son installation. Rappelons aussi que les segments de rollback sont nécessaires pour
effectuer le UNDO ou le ROLLBACK dʹune seule transaction sans pour autant recourir au journal interne qui est global à toutes les transactions.
Bases de données de référence
Les exemples utilisés pour illustrer les premières clauses SQL du présent chapitre se réfèrent à quelques bases de données dont le schéma et la sémantique sont présentés ci‐
dessous. Les versions récentes des SGBD utilisant lʹUNICODE devraient pouvoir éventuellement accepter les signes orthographiques nationaux dans les clauses SQL.
Pour simplifier la base, on convient dʹutiliser de préférence les minuscules non accentuées, mais en tolérant les exceptions pour des raisons de meilleure lisibilité.
BD1 : Ventes au détail
Cette extension de la base de données valide la contrainte référentielle qui est implémentée et active lors des transactions sur la base. Elle sera utilisée par la suite comme base de référence pour de plusieurs exercices SQL. La base est composée des tables Ventes et Inventaire.
Ventes : nom* article* qte* (table enfant)
Serge a1 3
Ted a2 5
Andrée a1 2
Serge a2 4
Erik a1 2
Serge a3 4
Valérie a7 3
Lucie a7 2
Serge a5 3
Serge a7 5
Christine a3 6
Serge a1 7
Cette contrainte référentielle est un cas particulier d’une contrainte d’inclusion plus générale qui spécifierait que tout article de la relation Ventes doit être inclus dans la projection de la table Inventaire sur l’attribut article. Une transaction sur la base ne concerne qu’un article en inventaire au moment de la vente, tandis que chaque article en inventaire peut faire l’objet de plusieurs transactions de vente.
Dans la table Inventaire, les attributs prixVente et cout partagent le même domaine de valeurs, mais avec une sémantique distincte marquée par un libellé respectif différent.
Tous les articles vendus sont inscrits dans lʹinventaire. Au moins un article disponible en inventaire n’a pas encore été vendu. Pour satisfaire l’hypothèse de la relation universelle qui impose l’unicité des libellés dans un schéma, les articles déjà vendus et ceux actuellement en inventaire peuvent être libellés respectivement Ventes.article et
Inventaire.article. Une transaction de vente est inscrite en notant le nom de l’acheteur, l’article et la quantité. La clé de la table Ventes est rendue volontairement complexe par l’absence d’un numéro de transaction. Dans ce schéma, elle est formée de tous les attributs.
Inventaire : article* prixVente cout (table parent)
a5 17 20
a1 10 5
a2 20 0
a7 15 15
a3 25 null
a16 46 34 + nouvel article
Figure 7.9
La table Inventaire fournit les articles en inventaire. L’absence de coût signifie que cet article n’est plus disponible. La contrainte référentielle est spécifiée par une clé étrangère mono‐attribut dans la table Ventes (soit article) portant le même libellé que la clé primaire dans la table parent Inventaire. La simplicité de la relation Inventaire et le choix de sa clé sous‐tendent que certains faits ne peuvent pas être représentés dans cette base.
Par exemple, deux articles identiques achetés à des coûts différents ne pourraient pas être représentés dans cet inventaire.
BD2 Gestion des stocks de pièces pour les transporteurs aériens
Cette deuxième base représente les stocks de pièces des transporteurs aériens répartis ici et là dans le monde pour la réparation de leurs avions.
Transporteur : mat* nom volPass villeSS permis
f1 Flyer 200 Londres 235
f2 Inter 100 Paris 160
f3 Airqc 300 Québec null
f4 Boac 200 Londres 190
f5 Delta 300 Boston 120
Un transporteur a un permis d’opération pour chaque avion q’il possède, une matricule, un siège social dans une ville donnée et un nom de société. Le permis d’un transporteur peut être révoqué temporairement auquel cas l’indicateur null est utilisé pour signifier l’absence de permis. Chaque transporteur peut déplacer un nombre maximum de passagers par jour (volPass).
Dans le cas de cette base BD2, l’hypothèse de la relation universelle est aussi vérifiée, car un libellé d’attribut n’a qu’une seule sémantique, peu importe la table où il apparaît.
Les attributs proprio et mat partagent le même domaine sémantique. En outre, l’attribut proprio peut être null comme cela est signalé par un null dans l’extension ci‐dessus.
Pieces : noP* description km (K) poids villeP proprio
p1 aileron 8500 12 Londres f3
p2 moteur 9900 50 Paris f5
p3 porte 6000 17 Rome f1
p4 radar 8000 14 Londres null
p5 train 5000 78 Paris f2
p6 télémètre 9000 36 Londres f2
Figure 7.10
La contrainte dʹinclusion (qui est dénommée DIN) est du genre référentiel et elle doit être valide à tout moment. De plus, le permis de vol international est unique et identifie le transporteur, mais il est possible d’avoir un transporteur qui ne l’a pas ou qui est en instance de l’obtenir (unicité de l’attribut avec valeur nulle autorisée). Lʹattribut permis ne peut donc pas être une clé, car il peut être nul. Les clés sont respectivement mat et noP. Les attributs proprio et mat ont le même domaine sémantique et font donc référence au même concept. Si la colonne proprio était ignorée, la table n’aurait pas de contrainte référentielle et les deux tables seraient sans association sémantique.
La ville du siège social du transporteur est nommée différemment (villeSS) de celle du dépôt de pièces (villeP). L’hypothèse de la relation universelle est donc vérifiée de facto.
Il y aurait une ambiguïté si, dans les deux relations, il y avait un même attribut ville ayant deux interprétations différentes. Avec la colonne proprio (comme clé étrangère) dont le domaine sémantique est partagé avec celui de mat, un lien est établi entre les deux tables et les jointures deviennent possibles. Avec ces deux tables, il serait aussi possible de définir un cluster indexé de placement des tuples pour que ceux qui partagent la même valeur de la clé du cluster (par exemple, la clé primaire et de la clé étrangère) soient rangés dans la même page.
BD3 Dotation des ressources humaines
Cette base implante une association (n‐m) entre deux classes au moyen d’une troisième relation ou table.
Postes : noPoste* description
j12 gérant
j34 électricien
j98 null
j21 mécano1
j55 contrôleur
j75 mécano2
Empl : noEmpl* nom prenom tauxH
P346 Audy Rudy 13.00
P456 Gagnon André 17.00
P345 Audy Michel 12.50
P651 Tremblay Robert 12.50
P762 Dussault Marc 13.25
P337 Bérube null 12.50
P450 Dion Fabrice 13.25
P535
P800
Joncas Vanjulier
Sylvie Julie
14.50 19.50
Assignations : noPoste* noEmpl* debut quart
j12 P456 21‐jan‐1992 soir
j34 P651 22‐mar‐1991 jour
j21 P762 23‐dec‐1990 nuit
j34 P345 24‐sep‐1994 jour
j75 P346 12‐oct‐1997 null
j55 P456 25‐jan‐1994 jour
j34 P337 21‐jan‐1992 nuit
j75
j34
P450 P800
27‐jan‐1994 10‐nov‐1995
null soir
* Indique un attribut primaire (i.e. un attribut inclus dans une clé) Figure 7.11
Le lien d’association complexe entre les deux tables est assuré par une troisième table Assignations. La troisième table utilisée pour implémenter lʹassociation a une clé primaire composée (noPoste, noEmpl); les deux clés étrangères distinctes dans cette table sont respectivement noPoste et noEmpl.
7.5 Schéma de la base de données
Le modèle conceptuel est transposé en un modèle logique (MLD) propre au SGBD par lʹentremise de règles de passage particulières. Le schéma du modèle logique est spécifié par les clauses SQL‐DDL qui définissent les tables de la base de données et leurs caractéristiques. Les contraintes dʹattribut, la clé primaire et la ou les clés étrangères dʹune relation sont aussi définies dans le schéma.
Création dʹune table et le typage des attributs
La création d’une table consiste à définir son schéma et à l’associer à un nom unique composé du compte propriétaire et du libellé de la table. Définir une table sous‐tend aussi la spécification de ses attributs typés, des contraintes d’intégrité associées aux attributs et, éventuellement, de son espace de table. Les types internes (type avec lequel une donnée est stockée dans la base de données) disponibles dans Oracle sont similaires à ceux spécifiés par le SQL‐92 avec cependant quelques différences. Par exemple, le type booléen n’est pas toujours implémenté ; il est cependant présent dans la version 9i de Oracle et de DB2.
Types internes dʹOracle pour les données
Les SGBD comme Oracle, DB2 et Informix sont capables de représenter les données avec une gamme assez étendue de types. Toutefois leurs types ne sont pas toujours aussi élaborés que ceux des langages de programmation de 3e génération. Une conversion s’imposer alors, opération qui devra être prise en charge par l’application!
Avec Oracle, les types suivants sont disponibles :
VARCHAR2(w), où w est la longueur de la chaîne, max. 2Ko, et 4Ko avec la version 8.
NUMBER(p, s), p est le nombre total de chiffres avec s chiffres après le point (scale).
LONG, données en caractères jusqu’à deux Go (image).
DATE (1), ce type comprend les éléments suivants : le siècle, l’année, le mois, le jour, l’heure, la minute, la seconde(voir (1)).
RAW (w), données en binaire, pour une longueur maximale de 255 octets;
LONG RAW, données en binaire, jusqu’à 2 Go.
ROWID, caractères hexadécimaux représentant l’adresse du tuple.
CHAR (w), où w est la longueur fixe de la chaîne avec un maximum de 255 o.
MLSLABEL, étiquette de système (pour la version Trusted Oracle).
FLOAT (b), pour les réels avec précision b.
CLOB, données de longueur variable codées sur 1 octet/caractère, mx 4Go.
BLOB, chaîne de bits, max. 4Go.
NCHAR, chaîne fixe de caractères NLS (alphabet national).
L’implémentation des types peut varier d’un manufacturier à l’autre avec la limitation classique pour le Float dans sa représentation des entiers et des réels.
(1) Le type DATE a un format externe bien connu, mais son format interne est bien
différent. Le passage de l’un à l’autre se fait par des fonctions spécialisées : TO_DATE(), TO_CHAR() et TRUNC(). La fonction TO_CHAR(), avec un gabarit approprié, permet dʹafficher la date dans le format externe souhaité et de supprimer le temps lors de la transposition de la date. Cela permet ainsi de faire des comparaisons fondées uniquement sur le jour, le mois et lʹannée: TO_CHAR(dateContrat, ʹYYYY‐MM‐DDʹ) ‐‐>
ʹ1999‐11‐24ʹ.
Conventions dʹécriture des contraintes de clé
Les tables sont créées avec une clé primaire (dite aussi principale) et éventuellement une ou plusieurs clés étrangères. Le nom d’une contrainte spécifiée lors de la création dʹune table doit être unique et peut être formé par simple convention d’écriture avec le préfixe cp_ ou pk_ pour la contrainte de clé primaire suivi du nom de la table. Pour une clé étrangère, le nom de la contrainte est préfixé par fk_, suivi du nom de la table enfant et au besoin, celui de la table parent. Exemple, fk_ouvrier_atelier, pour dénoter la contrainte référentielle entre la table Atelier et Ouvrier. Ainsi, le nom de la contrainte permet de l’associer au couple table enfant‐parent.
Voici la formulation du schéma de la table Ventes de la BD3 : CREATE TABLE Ventes(
nom VARCHAR2(15) NOT NULL, article VARCHAR2(10) NOT NULL, qte NUMBER(3),
CONSTRAINT pk_Ventes PRIMARY KEY (nom,article, qte), CONSTRAINT fk_Ventes_inventaire FOREIGN KEY(article) REFERENCES Inventaire (article) )
[Tablespace TS_user99 Storage initial 500M next 75M minextents 5 maxextents 20] ;
N.B. Les tuples de la table Ventes sont rangés dans lʹespace table TS_user_99 jusquʹà hauteur de 10 Go. Le reste de lʹespace sera occupé par dʹautres tables. La spécification de l’espace de données (tablespace) n’est pas nécessaire lorsque le rangement des tuples est fait automatiquement dans l’espace de données associé par défaut au compte de l’utilisateur.
Lorsque la clé primaire est simple, elle peut être aussi définie au niveau de lʹattribut.
CREATE TABLE Inventaire (
article VARCHAR2(10) CONSTRAINT cp_inventaire PRIMARY KEY,
prixVente NUMBER(5,2) NOT NULL, cout NUMBER(5,2) null)
PCTFREE 20 PCTUSED 75
[TABLESPACE TS_donnees1]; --table stockée dans TS_donnees1
La table est créée et les données seront stockées dans un espace de table nommé TS_donnees1. Si lʹespace de table nʹest pas identifié, lʹextension sera créée et placée automatiquement dans lʹespace de table SYSTEM. Ce dernier est créé par le SGBD pour y ranger les tables du dictionnaire. Il faut donc de préférence ne pas engorger cet espace en plaçant les données dans des espaces de table séparés stockés au besoin sur un disque différent.
CREATE TABLE Transporteur(
mat CHAR(3) NOT NULL,
nom VARCHAR2(15) NOT NULL, volPass NUMBER(3),
villeSS VARCHAR2(15), permis CHAR(3) NULL,
CONSTRAINT pk_transporteur PRIMARY KEY (mat)) [TABLESPACE TS_donnees_user]; ****
-- [] signifie non nécessaire selon le cas. Les données sont rangées dans le tablespace TS_donnees_user
CREATE TABLE Pieces (
noP CHAR(2) NOT NULL PRIMARY KEY, description VARCHAR2(15) NOT NULL, km NUMBER(4)NOT NULL,
poids NUMBER(2)NOT NULL,
VILLEP VARCHAR2(15) NOT NULL, proprio CHAR(3) NULL,
CONSTRAINT fk_transporteur_pieces FOREIGN KEY (proprio)
REFERENCES Transporteurs(mat)) [TABLESPACE TS_donnees_user];
CREATE TABLE Empl(
NOEmpl CHAR(4) NOT NULL PRIMARY KEY, -- si clé simple nom VARCHAR2(35) NOT NULL,
prenom VARCHAR2(25) NULL,
TAUXH NUMBER(5,2) NOT NULL check(tauxH > 10.00)) TABLESPACE TS_donnees_user;
CREATE TABLE Postes(
NOPoste CHAR(3) NOT NULL PRIMARY KEY, description VARCHAR2(45) null)
[TABLESPACE TS_donnees_user];
CREATE TABLE Assignations ( NOPoste CHAR(3) NOT NULL, NOEmpl CHAR(4)NOT NULL, debut DATE NOT NULL, quart VARCHAR2(6) NULL,
CONSTRAINT cp_Assignations PRIMARY KEY (noPoste, noEmpl),
CONSTRAINT fk_Assignations_empl FOREIGN KEY(NOEMPL) REFERENCES EMPL (noEmpl),
CONSTRAINT fk_Assignations_postes FOREIGN KEY (noPoste) REFERENCES Postes (noPoste)) TABLESPACE TS_donnees_user;
Le schéma de cette dernière table comprend une clé primaire et deux clés étrangères. Par la suite, le DBA ou le propriétaire de la base de données peut toujours modifier certains paramètres d’un schéma par la commande ALTER TABLE :
ALTER TABLE Postes ADD (description varchar2);
ALTER TABLE Postes DROP description; --avec la version 8
Les clés primaires sont qualifiées NOT NULL de sorte que si le chargement initial de la base de données est fait avec une clé primaire désactivée, les nulls seront quand même interdites de stockage. À la fin de lʹopération, la clé primaire est activée de nouveau afin dʹamorcer la construction ou la mise à jour de lʹindex‐système sous‐tendu par la clé
primaire. Cette façon de faire est plus rapide, puisquʹil nʹy a pas de mise à jour de lʹindex en cours de chargement, mais exige lʹabsence de clés dupliquées. Avec le NOT NULL, le chargement refusera tout tuple dont les attributs primaires ne sont pas valués, puisque ces données ne constituent pas une clé valide.
Les clés : primaire, étrangère et attribut UNIQUE
Une clé primaire limite la nature des tuples qui peuvent être rangés dans la base de données en interdisant les doublets. En effet, il ne peut pas y avoir deux tuples ayant la même valeur pour les attributs de la clé primaire. Cette contrainte est généralement placée à la fin de la spécification du schéma d’une table et est nommée de manière à la distinguer dans le dictionnaire. La clé primaire peut être simple ou composée. Voici un exemple dʹune clé composée :
CREATE table Assignation (
noEmpl number(2) not null, noPoste number (2) not null,
… ,
CONSTRAINT cp_EmplPoste PRIMARY KEY (noCours, section);
Lorsque la clé primaire est composée, elle peut être formulée pour avoir des attributs nuls, pourvu quʹun des attributs primaires soit non nul. Dans ce cas, la contrainte de clé primaire est implémentée par la clause UNIQUE(), laquelle permet de contraindre les valeurs pour quʹelles soient toutes différentes ou nulles pour un ou plusieurs attributs.
CREATE TABLE Employe (
nom varchar2(50) NOT NULL, noEquipe number(4) NULL, . . . )
Constraint U_NoBinome UNIQUE(nom, noEquipe) );
La paire dʹattributs (nom, noEquipe) doit avoir au moins une valeur pour l’attribut nom qui ne peut pas être nul. Toutefois, lʹattribut noEquipe peut être nul comme cela est autorisé par les UNIQUE et NOT NULL. Une contrainte étrangère peut être spécifiée en se référant a un attribut UNIQUE, donc à des attributs qui ne sont pas une clé primaire.
La clé étrangère simple ou complexe exprime une contrainte pour les tuples qui peuvent être ajoutés dans la table enfant et une autre contrainte sur la suppression des tuples dans la table parent. Soit la table ChoixCours avec une contrainte référentielle par rapport à la table parent CoursHoraire.
CoursHoraire(noCours*, section*, professeur) ChoixCours(matricule*, noCours*, section)
Create table ChoixCours(
matricule char(3) NOT NULL, noCours char(6),
section number(1),
constraint cp_choix_cours primary key (matricule, noCours),
CONSTRAINT fk_choix_cours_cours_horaire FOREIGN KEY(noCours, section)
REFERENCES CoursHoraire(noCours, section);
L’ajout d’un choix de cours particulier sous‐tend une référence à un cours‐horaire qui doit exister dans la base. La clé étrangère dans un tuple est soit entièrement composée de nulls, soit partiellement ou entièrement valuée, i.e. qu’au moins un des attributs a une valeur.
7.6 Implémentation des contraintes structurelles avec le langage SQL‐92
Les définitions ci‐dessus sont partiellement muettes en ce qui concerne les contraintes structurelles du MCD. Ceci est particulièrement important pour les tables avec des clés étrangères. En effet, la suppression dʹun tuple dans une table parent nʹest pas neutre par rapport à la table enfant. Quʹarrive‐t‐il aux tuples dépendants lors de la suppression ou de la mise à jour de la clé du tuple parent ? Reprenons lʹexemple du modèle simple ci‐
dessous dont le schéma correspondant est constitué de deux relations : Ville et Province.
Les contraintes du modèle imposent une suppression automatique des villes associées lorsque la province est supprimée.
Figure 7.12 Le modèle équivalent UML est le suivant :
Province(nomP*, populationP)
Ville(nomV*, populationV, dateCreationV, nomP) Figure 7.13
EstDans Ville
nomV*
populationV dateCreationV
Province nomP*
populationP
(1,1) (1,n)
Ville nomV*
populationV dateCreationV
Province nomP*
populationP 1..* EstDans 1
UML