Requêtes SQL 5 requêtes analysées
Détecte les joueurs ayant au moins 3 catégories statistiques ≥ 10 dans un même match (points, rebonds, passes, interceptions, contres).
SELECT p.first_name || ' ' || p.last_name AS joueur, g.game_date AS date_match, g.season AS saison, gs.points AS pts, gs.rebounds AS reb, gs.assists AS ast, gs.steals AS stl, gs.blocks AS blk FROM game_stats gs JOIN players p ON gs.player_id = p.player_id JOIN games g ON gs.game_id = g.game_id WHERE g.season = '2023-24' AND ( (CASE WHEN gs.points >= 10 THEN 1 ELSE 0 END) + (CASE WHEN gs.rebounds >= 10 THEN 1 ELSE 0 END) + (CASE WHEN gs.assists >= 10 THEN 1 ELSE 0 END) + (CASE WHEN gs.steals >= 10 THEN 1 ELSE 0 END) + (CASE WHEN gs.blocks >= 10 THEN 1 ELSE 0 END) ) >= 3 ORDER BY g.game_date, joueur;
Résultat obtenu
Comparaison des plans d'exécution
Plan hash: 2093995845 |* 5 | TABLE ACCESS FULL | GAME_STATS | | 6 | TABLE ACCESS BY ROWID| PLAYERS | |* 7 | INDEX UNIQUE SCAN | SYS_C008272 | |* 8 | INDEX UNIQUE SCAN | SYS_C008278 | |* 9 | TABLE ACCESS BY ROWID| GAMES | Problème : full scan GAME_STATS (40 lignes) Filtre season appliqué APRÈS le scan complet
Plan hash: 2205428426 | 6 | INDEX FULL SCAN | IDX_GS_GAME_ID | |* 9 | INDEX RANGE SCAN | IDX_GAMES_SEASON | |*10 | INDEX UNIQUE SCAN | SYS_C008272 | |* 5 | TABLE ACCESS BY ROWID| GAME_STATS | | 11 | TABLE ACCESS BY ROWID| PLAYERS | IDX_GAMES_SEASON filtre la saison EN PREMIER → Élimination du full scan sur GAME_STATS
Gains mesurés
Retourne les joueurs de taille ≥ 79 pouces (2m) ayant réalisé au moins une interception, avec le nombre de matchs concernés.
SELECT DISTINCT p.first_name || ' ' || p.last_name AS joueur, p.height_inches AS taille_pouces, ROUND(p.height_inches * 2.54, 1) AS taille_cm, COUNT(DISTINCT gs.game_id) AS nb_matchs FROM players p JOIN game_stats gs ON p.player_id = gs.player_id WHERE p.height_inches >= 79 AND gs.steals > 0 GROUP BY p.first_name, p.last_name, p.height_inches ORDER BY p.height_inches DESC;
Résultat obtenu
Comparaison des plans d'exécution
TABLE ACCESS FULL sur PLAYERS TABLE ACCESS FULL sur GAME_STATS 2 table scans (short tables) Filtre height_inches appliqué après scan complet
2 index range scans actifs idx_players_height → filtre >= 79 direct idx_gs_steals → filtre steals > 0 direct idx_gs_player_id → jointure accélérée
Calcule la somme des rebonds pris par tous les joueurs de Golden State sur la saison 2023-24.
SELECT t.city || ' ' || t.team_name AS equipe, g.season AS saison, SUM(gs.rebounds) AS total_rebonds FROM teams t JOIN players p ON p.team_id = t.team_id JOIN game_stats gs ON gs.player_id = p.player_id JOIN games g ON gs.game_id = g.game_id WHERE t.city = 'Golden State' AND g.season = '2023-24' GROUP BY t.city, t.team_name, g.season;
Résultat obtenu
Comparaison des plans d'exécution
15 table scans (short tables) TABLE ACCESS FULL sur TEAMS, GAMES, GAME_STATS Filtre city et season appliqués après scans complets 265 blocs lus en mémoire
3 index range scans actifs idx_teams_city → filtre city direct idx_games_season → filtre saison direct idx_gs_player_game → jointure couverte −91% de blocs lus
Trouve le joueur ayant marqué le plus de points dans un seul match, toutes saisons confondues.
SELECT p.first_name || ' ' || p.last_name AS joueur, g.game_date AS date_match, gs.points AS points_max FROM game_stats gs JOIN players p ON gs.player_id = p.player_id JOIN games g ON gs.game_id = g.game_id WHERE gs.points = ( SELECT MAX(points) FROM game_stats ) ORDER BY g.game_date;
Résultat obtenu
Comparaison des plans d'exécution
TABLE ACCESS FULL sur GAME_STATS (x2) Sous-requête MAX(points) scan complet 3 table scans (short tables) 44 blocs lus en mémoire
idx_gs_points → MAX() par lecture feuille B-tree INDEX FETCH BY KEY pour la valeur max Sous-requête résolue sans scan complet −59% de blocs lus
Trouve le joueur ayant cumulé le plus grand nombre de points sur l'ensemble de la saison 2023-24.
SELECT p.first_name || ' ' || p.last_name AS joueur, g.season AS saison, SUM(gs.points) AS total_points FROM game_stats gs JOIN players p ON gs.player_id = p.player_id JOIN games g ON gs.game_id = g.game_id WHERE g.season = '2023-24' GROUP BY p.first_name, p.last_name, g.season HAVING SUM(gs.points) = ( SELECT MAX(SUM(gs2.points)) FROM game_stats gs2 JOIN games g2 ON gs2.game_id = g2.game_id WHERE g2.season = '2023-24' GROUP BY gs2.player_id ) ORDER BY total_points DESC;
Résultat obtenu
Comparaison des plans d'exécution
6 table scans (short tables) Sous-requête MAX(SUM()) sans index TABLE ACCESS FULL sur GAME_STATS (x2) 62 blocs lus en mémoire
2 index range scans actifs idx_games_season → filtre saison direct idx_gs_gameid_player_points → couvre JOIN + SUM INDEX FETCH BY KEY pour la sous-requête −23% de blocs lus
Index créés Justification et types
| Nom de l'index | Table | Colonnes | Type | Requête | Justification |
|---|---|---|---|---|---|
idx_games_season |
games | season |
B-tree | R1 | INDEX RANGE SCAN sur la saison — filtre les matchs avant de joindre game_stats |
idx_gs_game_id |
game_stats | game_id |
B-tree | R1 | Élimine le TABLE ACCESS FULL — permet le MERGE JOIN via l'index |
idx_gs_player_id |
game_stats | player_id |
B-tree | R1 | Optimise la jointure game_stats → players |
idx_players_height |
players | height_inches |
B-tree | R2 | INDEX RANGE SCAN sur height ≥ 79 — évite TABLE ACCESS FULL sur PLAYERS |
idx_gs_steals |
game_stats | steals |
B-tree | R2 | Filtre steals > 0 sans scan complet de GAME_STATS |
idx_teams_city |
teams | city |
B-tree | R3 | Accès direct à 'Golden State' sans parcourir toute la table TEAMS |
idx_games_season |
games | season |
B-tree | R3, R5 | Filtre saison '2023-24' en amont — réutilisé par R5 |
idx_gs_player_game |
game_stats | player_id, game_id |
Composite | R3 | Couvre les deux jointures player et game simultanément |
idx_gs_points |
game_stats | points |
B-tree | R4 | MAX(points) résolu par lecture de la feuille droite du B-tree en O(log n) |
idx_gs_gameid_player_points |
game_stats | game_id, player_id, points |
Composite | R5 | Couvre jointure + GROUP BY + SUM(points) — index de couverture |
Comparaison des performances Consistent gets avant / après
Métrique : consistent gets issue de SET AUTOTRACE ON.
Plus la valeur est basse, moins Oracle lit de blocs en mémoire.
Bilan d'optimisation R1 → R5
Oracle lisait les 40 lignes sans index. Après, il utilise IDX_GS_GAME_ID (INDEX FULL SCAN) combiné à IDX_GAMES_SEASON (INDEX RANGE SCAN) via un MERGE JOIN.
Les filtres height_inches ≥ 79 et steals > 0 utilisent désormais des INDEX RANGE SCAN au lieu de TABLE ACCESS FULL.
La combinaison idx_teams_city + idx_games_season + idx_gs_player_game couvre les 4 tables de la jointure. Oracle filtre Golden State et la saison en premier, réduisant massivement le volume traité.
Le MAX(points) est résolu par lecture directe de la feuille droite du B-tree en O(log n) au lieu d'un scan complet de la table.
L'index idx_gs_gameid_player_points couvre la jointure, le GROUP BY et le SUM(points) en un seul accès. La sous-requête MAX(SUM()) bénéficie aussi de idx_games_season.
Tout INSERT dans game_stats, games, players ou teams met à jour les index correspondants. Sur de petites tables l'impact est négligeable, mais sur des millions de lignes il faut désactiver les index pendant les chargements massifs (ALTER INDEX ... UNUSABLE).
Équipe projet
Sahi Nour El Imene
Setup Oracle · Import BD NBA · Requête 1 (triple double)
Maouche Lina
Requêtes 2, 3, 4, 5 · Plans d'exécution · Index