Lecon 10.2 · Temps de lecture : ~10 min
Cette lecon presente les bases de l'ecriture de requetes SQL performantes. Vous allez apprendre a eviter la charge inutile sur la base, comprendre pourquoi SELECT * ralentit souvent l'execution, et filtrer les donnees correctement. Nous allons etudier des techniques pratiques pour accelerer les requetes sur de gros volumes. A la fin, vous saurez ecrire un SQL efficace et respectueux des ressources serveur.
Dans la lecon precedente, nous avons parle de lisibilite pour les humains. Mais une requete SQL doit aussi etre efficace pour le moteur de base de donnees. Meme un code bien formate peut etre lent s'il force le serveur a faire trop de travail.
L'efficacite d'une requete impacte directement la vitesse des applications et des rapports. Sur des systemes a forte charge, la difference entre une requete "fonctionnelle" et "optimisee" peut etre enorme.
Les SGBD modernes disposent d'optimiseurs puissants, mais ils ne connaissent pas votre logique metier et ne corrigent pas tout. La responsabilite de la qualite SQL reste cote developpeur.
Une cause frequente de lenteur est le transfert de donnees inutiles entre serveur et client.
SELECT *SELECT * est pratique pour explorer, mais il faut l'eviter dans le code final.
-- Mauvais
SELECT * FROM film;
-- Mieux
SELECT film_id, title, release_year
FROM film;
La facon de limiter les lignes determine le volume de travail du SGBD.
Appliquez WHERE avant les operations lourdes. Moins de lignes en amont signifie des JOIN et GROUP BY plus rapides.
WHERE (requetes SARGable)Pour profiter des index, les predicates WHERE doivent etre SARGable. Si vous appliquez une fonction sur une colonne indexee, l'optimiseur risque de ne pas utiliser l'index efficacement.
-- Lent (Non-SARGable)
SELECT count(*)
FROM rental
WHERE YEAR(rental_date) = 2005;
-- Rapide (SARGable)
SELECT count(*)
FROM rental
WHERE rental_date >= '2005-01-01' AND rental_date < '2006-01-01';
JOINLes jointures sont parmi les operations les plus couteuses.
CROSS JOIN sans besoin reel.EXISTS pour des verifications d'existence simples.-- Moins efficace
SELECT DISTINCT c.first_name, c.last_name
FROM customer c
JOIN payment p ON c.customer_id = p.customer_id;
-- Plus efficace pour un test d'existence
SELECT c.first_name, c.last_name
FROM customer c
WHERE EXISTS (
SELECT 1 FROM payment p WHERE p.customer_id = c.customer_id
);
LIMIT pendant les testsPendant le debogage, utilisez LIMIT pour eviter de retourner des millions de lignes.
SELECT customer_id, first_name, last_name
FROM customer
WHERE active = 1
LIMIT 10;
Supposons que nous cherchions les films loues plus de 30 fois dans une categorie donnee.
Approche moins efficace :
SELECT f.title, COUNT(r.rental_id)
FROM film f
JOIN inventory i ON f.film_id = i.film_id
JOIN rental r ON i.inventory_id = r.inventory_id
JOIN film_category fc ON f.film_id = fc.film_id
JOIN category c ON fc.category_id = c.category_id
WHERE c.name = 'Action'
GROUP BY f.title
HAVING COUNT(r.rental_id) > 30;
Approche plus efficace : Si l'ID de categorie est connu, on evite une jointure inutile.
SELECT f.title, COUNT(r.rental_id) AS rental_count
FROM film f
JOIN film_category fc ON f.film_id = fc.film_id
JOIN inventory i ON f.film_id = i.film_id
JOIN rental r ON i.inventory_id = r.inventory_id
WHERE fc.category_id = 1 -- Utiliser l'ID plutot que la chaine
GROUP BY f.film_id, f.title
HAVING COUNT(r.rental_id) > 30;
Remarque : filtrer sur un identifiant numerique est souvent plus rapide que filtrer sur un libelle texte.
Points cles a retenir de cette lecon :
SELECT * en production.EXISTS a JOIN pour des tests d'existence.LIMIT pour l'exploration et le debug.SELECT * est-il problematique en production ?Il retourne des colonnes inutiles, augmente le trafic et peut degrader les plans d'execution. Lister explicitement les colonnes est plus sur.
Une condition SARGable permet une recherche via index. Les fonctions appliquees aux colonnes indexees bloquent souvent cet avantage.
EXISTS plutot que JOIN ?Quand vous voulez seulement verifier l'existence d'une ligne liee, sans recuperer de colonnes de la table secondaire.
Je verifie SELECT *, la selectivite des filtres WHERE, puis les predicates non SARGable. Ensuite j'analyse les jointures et le volume de lignes traitees.
Parce que cela reduit les lignes impliquees dans les jointures, tris et agregations, ce qui baisse le cout global du plan.
JOIN et EXISTS ?JOIN combine les jeux de lignes et est necessaire si vous avez besoin de colonnes des deux tables. EXISTS est souvent plus efficace pour un simple test oui/non.
Dans la prochaine lecon, nous allons analyser l'execution plus en profondeur et voir comment les index accelerent les requetes au niveau physique.
-> Lecon 10.3 : Comprendre les methodes d'optimisation des requetes