Le carnet On est
Annale · session normale

Examen TAD 2022 — 2023

Trois parties équilibrées : administration Oracle (entreprise de bonbons), PL/SQL en cascade, et BDDR sur centre de formation 3 sites. La partie I touche directement aux droits, rôles et vues — base de CM1.

2h · ING2 SIE I. Admin — 5 pts · II. PL/SQL — 8 pts · III. BDDR — 7 pts 12 mai 2023

1. Le sujet

📥 Télécharger  ·  ↗ Ouvrir en plein écran

2. Notions mobilisées

PartieQuestionNotion principaleChapitre
I. Admin1.a-cCréation users, rôles, attributionCM1 — Rôles & privilèges
1.dPermissions effectives + isolation transactionsCM1 · CM3
2.Vue logique avec jointuresCM1 — Vues
II. PL/SQL1.Génération auto de clé (séquence + trigger)CM5
2.Fonction stockée avec agrégatCM6
3.Trigger garde-fou de cohérenceCM5
4.Procédure + curseurs imbriquésCM6
III. BDDR1.Modèle réparti, fragmentation H + VCM4
2.Database linkCM4
3.Vue matérialisée répliquéeCM4
4.Coût des indexesCM2

3. Partie I — administration de la base (5 pts)

Contexte Entreprise de fabrication de bonbons. Schéma Oracle « organisation » avec : DIVISION(codediv, nomdiv), PROJET(numproj, nomproj, budget, codediv), SERVICE(codeserv, surfaceserv, nbBureaux, codediv), SALARIE(numsal, nomsal, adresse, qualification, codeserv), TRAVAILLESUR(numproj, numsal).

1.a — Créer deux utilisateurs (0.5 pt)

I · 1a Créer deux utilisateurs : Dirk Projet (Directeur de Projet, de schéma « dproje ») et Gérard Reen (Chef de Division, de schéma « green »). Ils ont comme mot de passe leur nom de schéma.

CREATE USER dproje IDENTIFIED BY dproje;
CREATE USER green  IDENTIFIED BY green;

-- Sans ces grants, les utilisateurs ne pourront meme pas se connecter
GRANT CREATE SESSION TO dproje, green;

1.b — Créer deux rôles (1 pt)

I · 1b Créer les rôles suivants :
— Rôle « ChefDivision » qui a tous les accès à toutes les tables.
— Rôle « ChefProjet » qui peut consulter toutes les tables et ajouter/supprimer des salariés à un projet.

-- Rolle ChefDivision : tous les droits sur les 5 tables
CREATE ROLE ChefDivision;
GRANT ALL ON organisation.DIVISION     TO ChefDivision;
GRANT ALL ON organisation.PROJET       TO ChefDivision;
GRANT ALL ON organisation.SERVICE      TO ChefDivision;
GRANT ALL ON organisation.SALARIE      TO ChefDivision;
GRANT ALL ON organisation.TRAVAILLESUR TO ChefDivision;

-- Rolle ChefProjet : SELECT partout + INSERT/DELETE sur TRAVAILLESUR
CREATE ROLE ChefProjet;
GRANT SELECT ON organisation.DIVISION     TO ChefProjet;
GRANT SELECT ON organisation.PROJET       TO ChefProjet;
GRANT SELECT ON organisation.SERVICE      TO ChefProjet;
GRANT SELECT ON organisation.SALARIE      TO ChefProjet;
GRANT SELECT, INSERT, DELETE ON organisation.TRAVAILLESUR TO ChefProjet;

1.c — Affecter les rôles (0.5 pt)

I · 1c Affecter les rôles aux utilisateurs.

GRANT ChefProjet   TO dproje;
GRANT ChefDivision TO green;

1.d — Questions de raisonnement (1 pt)

1.d.i Est-ce que Dirk Proje peut affecter des salariés de son projet à un service ?

Non. Affecter un salarié à un service revient à faire UPDATE SALARIE SET codeserv = ?. Le rôle ChefProjet de Dirk ne contient que SELECT sur SALARIE — pas de UPDATE. Référence : modèle des privilèges objet du CM1.

1.d.ii Dans une session, Dirk Proje est en train d'associer des salariés aux services. Dans une autre session, il vérifie que tous ces salariés travaillent sur le même projet. Peut-il voir, dans la 2de session, les affectations qu'il réalise dans les services ?

Non — tant que la 1re session n'a pas commité. Le CM3 définit la cohérence de lecture : chaque transaction voit la base telle qu'elle était au démarrage de sa requête. Les modifications non encore validées par COMMIT dans la session 1 sont invisibles à la session 2.
Note : la question 1.d.i indique en plus que Dirk ne peut techniquement pas modifier SALARIE — donc le scénario suppose qu'il a un autre rôle ou qu'on raisonne en théorie.

2 — Vue sal_Drag_MandMs (2 pts)

I · 2 Écrire la vue « sal_Drag_MandMs » permettant de ne montrer que les salariés travaillant sur le projet de nom « MandMs », appartenant à la division de nom « Dragées » et installé dans le service « 27 ».

CREATE OR REPLACE VIEW sal_Drag_MandMs AS
   SELECT s.numsal, s.nomsal, s.adresse, s.qualification
   FROM SALARIE s
   JOIN TRAVAILLESUR t  ON s.numsal   = t.numsal
   JOIN PROJET p        ON t.numproj  = p.numproj
   JOIN SERVICE serv    ON s.codeserv = serv.codeserv
   JOIN DIVISION d      ON p.codediv  = d.codediv
   WHERE p.nomproj  = 'MandMs'
     AND d.nomdiv   = 'Dragees'
     AND serv.codeserv = 27;

La division est référencée à la fois par PROJET et SERVICE — on choisit ici de la lier via PROJET. Si l'on voulait vérifier en plus que le service appartient à la même division que le projet, on rajouterait AND serv.codediv = p.codediv.

4. Partie II — PL/SQL (8 pts)

1 — Génération automatique de clés (1 pt)

II · 1 Rappeler comment les clés de certaines tables peuvent être générées automatiquement.

Selon le CM5, le pattern Oracle est en deux étapes :

  1. Créer une séquence, générateur d'entiers monotones :
CREATE SEQUENCE seq_projet
   START WITH 1
   INCREMENT BY 1
   NOCACHE NOCYCLE;
  1. Créer un trigger BEFORE INSERT qui pose la valeur de la séquence sur :new.<clé> :
CREATE OR REPLACE TRIGGER trig_id_projet
BEFORE INSERT ON PROJET
FOR EACH ROW
BEGIN
   :new.numproj := seq_projet.NEXTVAL;
END;

Depuis Oracle 12c, la clause GENERATED BY DEFAULT AS IDENTITY dans le CREATE TABLE remplit le même rôle — mais elle n'est pas couverte par nos CMs.

2 — Fonction NbProjets (2 pts)

II · 2 Écrire une fonction « NbProjets », avec le numéro de matricule du salarié en paramètre, qui renvoie le nombre de projets sur lequel travaille ce salarié.

Pattern fonction stockée avec agrégat (CM6) — la fonction respecte ici la sémantique stricte : elle retourne une valeur, n'a aucun effet de bord.

CREATE OR REPLACE FUNCTION NbProjets(p_matricule IN NUMBER)
RETURN NUMBER
IS
   v_nb NUMBER;
BEGIN
   SELECT COUNT(*) INTO v_nb
   FROM TRAVAILLESUR
   WHERE numsal = p_matricule;

   RETURN v_nb;
END;

Appel : SELECT NbProjets(123) FROM dual;

3 — Trigger : projet dans la division du salarié (2 pts)

II · 3 Écrire un trigger qui, lorsqu'on affecte un salarié à un projet, vérifie que le projet est bien affecté à la division à laquelle appartient le salarié et remonte une erreur sinon.

Garde-fou : il faut joindre SALARIE → SERVICE → DIVISION et PROJET → DIVISION, puis comparer.

CREATE OR REPLACE TRIGGER trig_coherence_division
BEFORE INSERT ON TRAVAILLESUR
FOR EACH ROW
DECLARE
   v_div_sal  NUMBER;
   v_div_proj NUMBER;
BEGIN
   -- Division du salarie (via son service)
   SELECT serv.codediv INTO v_div_sal
   FROM SALARIE sal
   JOIN SERVICE serv ON sal.codeserv = serv.codeserv
   WHERE sal.numsal = :new.numsal;

   -- Division du projet
   SELECT codediv INTO v_div_proj
   FROM PROJET
   WHERE numproj = :new.numproj;

   IF v_div_sal <> v_div_proj THEN
      RAISE_APPLICATION_ERROR(-20300,
         'Le salarie n''appartient pas a la division du projet');
   END IF;
END;

4 — Procédure infoDivision avec curseurs (3 pts)

II · 4 Écrire une procédure « infoDivision » qui prend en entrée un code division et liste les projets qui lui sont soumis et, pour chacun, les salariés qui travaillent dessus.

Pattern curseur imbriqué (CM6) : un curseur sur les projets, et dans la boucle, un autre curseur sur les salariés du projet courant.

CREATE OR REPLACE PROCEDURE infoDivision(p_codediv IN NUMBER)
IS
   CURSOR c_proj IS
      SELECT numproj, nomproj, budget
      FROM PROJET
      WHERE codediv = p_codediv;

   CURSOR c_sal(p_proj NUMBER) IS
      SELECT s.numsal, s.nomsal, s.qualification
      FROM SALARIE s
      JOIN TRAVAILLESUR t ON s.numsal = t.numsal
      WHERE t.numproj = p_proj;
BEGIN
   FOR p IN c_proj LOOP
      DBMS_OUTPUT.PUT_LINE('-- Projet ' || p.numproj
                       || ' : ' || p.nomproj
                       || ' (budget ' || p.budget || ')');

      FOR s IN c_sal(p.numproj) LOOP
         DBMS_OUTPUT.PUT_LINE('   . ' || s.numsal
                          || ' - ' || s.nomsal
                          || ' (' || s.qualification || ')');
      END LOOP;
   END LOOP;
END;

Le curseur paramétré c_sal(p_proj NUMBER) est exactement le pattern montré au CM6. Les boucles FOR … IN cur LOOP gèrent OPEN, FETCH et CLOSE automatiquement.

5. Partie III — bases de données réparties (7 pts)

Contexte — Data University Centre de formation sur 3 sites (Paris, Bordeaux, Lille). Tables : Formateur, Site, Inscrit, Formation, Module, FormationModule, FormationSession, InscriptionSession, Enseigne, Evaluation.
Point clé : « dans l'un des sites, certains formateurs définissent de nouvelles formations » → ce site est maître pour Formation/Module/FormationModule.

1 — Modèle de bases réparties (3 pts)

III · 1 Proposer un modèle de bases de données réparties sur les 3 sites, et justifier vos choix.

TableLocalisationTypeJustification
Site Site maître (Paris) + répliquée partout Référentiel Très peu de MAJ, lecture massive depuis les 3 sites → VM rafraîchie.
Formation, Module, FormationModule Site maître (Paris) Centralisée Création/modification réservée à un seul site, lecture partout via DB link ou VM.
Formateur Fragmenté par idSite H primaire Chaque formateur est rattaché à un site (FK idSite).
Inscrit Fragmenté par idSite H primaire Chaque inscrit est inscrit à un site.
FormationSession Fragmenté par site H primaire Une session est tenue dans un site donné (à dériver via Enseigne ou par convention de FS).
InscriptionSession, Enseigne, Evaluation Suivent FormationSession H dérivée Tables associatives — fragmentation dérivée par semi-jointure sur idFS.

Justifications globales (CM4) :

  • Locality of access — les sessions, inscriptions, évaluations vivent au site qui les organise → fragmentation H par site = traffic réseau minimal.
  • Source unique de vérité pour le catalogue — un seul site édite les Formations et Modules → centralisation maître/esclave.
  • Site = référentiel quasi statique → réplication par vue matérialisée (voir question 3).

2 — Accès distant (1 pt)

III · 2 Que faut-il faire pour qu'un apprenant ou un formateur d'un site puisse accéder à la base de données sur un autre site ?

Créer un database link. Selon le CM4, un DB link Oracle est un objet qui décrit la connexion à une autre base (chaîne de connexion + credentials). Il permet d'utiliser des objets distants comme s'ils étaient locaux, via la syntaxe table@nom_link.
-- Sur le site Bordeaux, on cree un link vers Paris
CREATE DATABASE LINK db_paris
CONNECT TO user_distant IDENTIFIED BY mdp
USING 'paris_service';

-- Puis on requete les formations centralisees comme localement :
SELECT * FROM Formation@db_paris;

3 — Optimiser la consultation du catalogue (2 pts)

III · 3 Sur un site quelconque, les formateurs seront souvent amenés à afficher le catalogue de formation. Que préconisez-vous pour optimiser cette requête ?

Une vue matérialisée répliquée. Le catalogue change peu mais est lu massivement → cas idéal de la réplication par VM (CM4). Chaque site stocke une copie locale du catalogue, automatiquement rafraîchie depuis le site maître.
-- Sur chaque site (Bordeaux, Lille), repliquer le catalogue
CREATE MATERIALIZED VIEW catalogue_local
REFRESH FAST ON DEMAND
AS
   SELECT f.idFormation, f.nom, f.descriptif,
          m.idModule, m.nom AS module, m.nbHeures
   FROM Formation@db_paris f
   JOIN FormationModule@db_paris fm ON f.idFormation = fm.idFormation
   JOIN Module@db_paris m   ON fm.idModule    = m.idModule;

Bénéfices (CM4) :

  • Lecture locale ultra-rapide
  • Disponibilité même si le réseau est indisponible
  • Coût réseau minimal (seulement aux rafraîchissements)

4 — Pourquoi pas tout indexer (1 pt)

III · 4 Pourquoi n'indexe-t-on pas tous les champs d'une Base de données ?

D'après le CM2, un index a trois coûts qui interdisent de tout indexer :

💾 Espace disque
Chaque index est un objet physique stocké en plus de la table. Indexer toutes les colonnes peut multiplier la volumétrie par 3-5×.
⏱ Surcoût en écriture
Chaque INSERT, UPDATE, DELETE doit mettre à jour tous les indexes touchés. Sur OLTP intensif, c'est rédhibitoire.
🎯 Inutilité sur faible sélectivité
Un B-tree sur une colonne avec peu de valeurs distinctes (booléen, sexe) coûte plus qu'il ne rapporte. Idem pour les colonnes jamais utilisées en filtre.
🤔 Optimiseur peut se tromper
Trop d'indexes brouille les choix de l'optimiseur — il peut prendre un mauvais plan d'exécution.

Règle pratique du CM2 : indexer les colonnes utilisées dans les clauses WHERE, JOIN, ORDER BY — pas les autres.

Bilan rapide

📌 Pattern central cette année
Curseurs imbriqués (infoDivision) — exactement le pattern du TP7. Bonne occasion de réviser FOR rec IN cur LOOP.
🎯 Cible "compromis" récurrente
L'arbitrage centralisé vs fragmenté revient à chaque BDDR : table de référentiel rare-MAJ → réplication / sessions actives par site → fragmentation H.