Guide complet de MySQL EXPLAIN

Présentation d'EXPLAIN

Cet article explique comment utiliser la commande EXPLAIN pour obtenir le plan d'exécusion d'une requête SELECT. Grâce à EXPLAIN, nous pouvons connaître les informations suivantes : l'ordre de lecture des tables, le type d'opération de lecture, les index possibles, les index réellement utilisés, les références entre tables, et le nombre estimé de lignes que l'optimiseur doit examiner.

Voici un exemple d'utilisation d'EXPLAIN :

Ajoutez le mot-clé EXPLAIN avant une instruction SELECT. MySQL place alors un marqueur sur la requête : au lieu d'exécuter la requête elle-même, il renvoie les informations du plan d'exécution. Toutefois, si la clause FROM contient une sous-requête, celle-ci est tout de même exécutée et son résultat est stocké dans une table temporaire.

mysql> EXPLAIN SELECT * FROM acteur;
+----+-------------+--------+------+---------------+------+---------+------+------+-------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | acteur | ALL  | NULL          | NULL | NULL    | NULL |    3 | NULL  |
+----+-------------+--------+------+---------------+------+---------+------+------+-------+

Pour chaque table utilisée dans la requête, une ligne est affichée. Par exemple, si deux tables sont jointes avec JOIN, deux lignes apparaîtront. La notion de « table » est large : cela peut être une sous-requête, un résultat d'UNION, etc.

Il existe deux variantes d'EXPLAIN :

  1. EXPLAIN EXTENDED : fournit des informations supplémentaires sur l'optimisation. Après son exécution, la commande SHOW WARNINGS affiche la requête optimisée, ce qui permet de comprendre ce que l'optimiseur a modifié. Une colonne filtered apparaît (pourcentage) : rows * filtered/100 estime le nombre de lignes qui seront jointes avec la table précédente du plan d'exécution.
mysql> EXPLAIN EXTENDED SELECT * FROM film WHERE identifiant = 1;
+----+-------------+-------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | film  | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+----------+-------+

mysql> SHOW WARNINGS;
+-------+------+--------------------------------------------------------------------------------+
| Level | Code | Message                                                                        |
+-------+------+--------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select '1' AS `identifiant`,'film1' AS `nom` from `test`.`film` where 1 |
+-------+------+--------------------------------------------------------------------------------+
  1. EXPLAIN PARTITIONS : ajoute une colonne partitions qui indique les partitions concernées si la requête porte sur une table partitionnée.

Les colonnes d'EXPLAIN

Détaillons maintenant chaque colonne.

1. Colonne id

Le numéro id est le numéro de séquence du SELECT. Il y a autant d'que deSELECTdans la requête, et l'ordre suit l'apparition desSELECT. MySQL classe les requêtes en deux catégories : simples et complexes. Les requêtes complexes se divisent en trois types : sous-requête simple, table dérivée (sous-requête dans FROM) et requête UNION.

a) Sous-requête simple

mysql> EXPLAIN SELECT (SELECT 1 FROM acteur LIMIT 1) FROM film;
+----+-------------+--------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys | key      | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+---------------+----------+---------+------+------+-------------+
|  1 | PRIMARY     | film   | index | NULL          | idx_nom  | 33      | NULL |    3 | Using index |
|  2 | SUBQUERY    | acteur | index | NULL          | PRIMARY  | 4       | NULL |    3 | Using index |
+----+-------------+--------+-------+---------------+----------+---------+------+------+-------------+

b) Sous-requête dans FROM (table dérivée)

mysql> EXPLAIN SELECT identifiant FROM (SELECT identifiant FROM film) AS derivee;
+----+-------------+------------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table      | type  | possible_keys | key      | key_len | ref  | rows | Extra       |
+----+-------------+------------+-------+---------------+----------+---------+------+------+-------------+
|  1 | PRIMARY     | <derivee2> | ALL   | NULL          | NULL     | NULL    | NULL |    3 | NULL        |
|  2 | DERIVED     | film       | index | NULL          | idx_nom  | 33      | NULL |    3 | Using index |
+----+-------------+------------+-------+---------------+----------+---------+------+------+-------------+

Cette requête crée une table temporaire aliasée derivee, utilisée par le SELECT externe.

c) Requête UNION

mysql> EXPLAIN SELECT 1 UNION ALL SELECT 1;
+----+--------------+------------+------+---------------+------+---------+------+------+-----------------+
| id | select_type  | table      | type | possible_keys | key  | key_len | ref  | rows | Extra           |
+----+--------------+------------+------+---------------+------+---------+------+------+-----------------+
|  1 | PRIMARY      | NULL       | NULL | NULL          | NULL | NULL    | NULL | NULL | No tables used  |
|  2 | UNION        | NULL       | NULL | NULL          | NULL | NULL    | NULL | NULL | No tables used  |
| NULL | UNION RESULT | <union1,2> | ALL  | NULL          | NULL | NULL    | NULL | NULL | Using temporary |
+----+--------------+------------+------+---------------+------+---------+------+------+-----------------+

Le résultat de l'UNION est toujours placé dans une table temporaire anonyme (d'où un id NULL).

2. Colonne select_type

Indique si la ligne correspond à une requête simple ou complexe, et dans ce dernier cas, de quel type.

  • SIMPLE : requête simple, sans sous-requête ni UNION.
mysql> EXPLAIN SELECT * FROM film WHERE identifiant = 2;
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
|  1 | SIMPLE      | film  | const | PRIMARY       | PRIMARY | 4       | const |    1 | NULL  |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
  • PRIMARY : le SELECT le plus externe d'une requête complexe.
  • SUBQUERY : sous-requête dans un SELECT (pas dans FROM).
  • DERIVED : sous-requête dans FROM, dont le résultat est stocké dans une table temporaire (table dérivée).

Exemple illustrant PRIMARY, SUBQUERY et DERIVED :

mysql> EXPLAIN SELECT (SELECT 1 FROM acteur WHERE identifiant = 1) FROM (SELECT * FROM film WHERE identifiant = 1) AS derivee;
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table      | type   | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------+
|  1 | PRIMARY     | <derivee3> | system | NULL          | NULL    | NULL    | NULL  |    1 | NULL        |
|  3 | DERIVED     | film       | const  | PRIMARY       | PRIMARY | 4       | const |    1 | NULL        |
|  2 | SUBQUERY    | acteur     | const  | PRIMARY       | PRIMARY | 4       | const |    1 | Using index |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------+
  • UNION : deuxième SELECT (et suivants) dans une UNION.
  • UNION RESULT : SELECT qui récupère le résultat depuis la table temporaire de l'UNION.

Exemple :

mysql> EXPLAIN SELECT 1 UNION ALL SELECT 1;
+----+--------------+------------+------+---------------+------+---------+------+------+-----------------+
| id | select_type  | table      | type | possible_keys | key  | key_len | ref  | rows | Extra           |
+----+--------------+------------+------+---------------+------+---------+------+------+-----------------+
|  1 | PRIMARY      | NULL       | NULL | NULL          | NULL | NULL    | NULL | NULL | No tables used  |
|  2 | UNION        | NULL       | NULL | NULL          | NULL | NULL    | NULL | NULL | No tables used  |
| NULL | UNION RESULT | <union1,2> | ALL  | NULL          | NULL | NULL    | NULL | NULL | Using temporary |
+----+--------------+------------+------+---------------+------+---------+------+------+-----------------+

3. Colonne table

Indique la table à laquelle la ligne se réfère. Si la clause FROM contient une sous-requête, la colonne table a le format <deriveeN>, signifiant que la requête dépend de la ligne avec id = N (celle-ci sera exécutée en premier). Pour UNION RESULT, la valeur est <union1,2> où 1 et 2 sont les id des SELECT participants.

4. Colonne type

Représente le type d'accès aux lignes, c'est-à-dire comment MySQL trouve les lignes dans la table. Du plus optimal au moins optimal :

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

NULL : MySQL peut résoudre la requête pendant l'optimisation sans accéder à la table ni à l'index. Exemple : pour obtenir la valeur minimale d'une colonne indexée.

mysql> EXPLAIN SELECT MIN(identifiant) FROM film;
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                        |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
|  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | Select tables optimized away |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+

const, system : MySQL optimise la condition pour la transformer en constante (voir SHOW WARNINGS). Utilisé lorsque toutes les colonnes d'une clé primaire ou d'un index unique sont comparées à des constantes. Au plus une ligne correspondante, lecture rapide.

mysql> EXPLAIN EXTENDED SELECT * FROM (SELECT * FROM film WHERE identifiant = 1) AS tmp;
+----+-------------+------------+--------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table      | type   | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+----------+-------+
|  1 | PRIMARY     | <derivee2> | system | NULL          | NULL    | NULL    | NULL  |    1 |   100.00 | NULL  |
|  2 | DERIVED     | film       | const  | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+------------+--------+---------------+---------+---------+-------+------+----------+-------+

mysql> SHOW WARNINGS;
+-------+------+---------------------------------------------------------------+
| Level | Code | Message                                                       |
+-------+------+---------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select '1' AS `identifiant`,'film1' AS `nom` from dual |
+-------+------+---------------------------------------------------------------+

eq_ref : Toutes les colonnes d'un index primaire ou unique sont utilisées dans une jointure. Au plus une ligne correspondante. C'est le meilleur type après const. N'apparaît pas dans un simple SELECT.

mysql> EXPLAIN SELECT * FROM film_acteur LEFT JOIN film ON film_acteur.film_id = film.identifiant;
+----+-------------+------------+--------+-------------------+-------------------+---------+---------------------------+------+-------------+
| id | select_type | table      | type   | possible_keys     | key               | key_len | ref                       | rows | Extra       |
+----+-------------+------------+--------+-------------------+-------------------+---------+---------------------------+------+-------------+
|  1 | SIMPLE      | film_acteur | index  | NULL              | idx_film_acteur_id | 8       | NULL                      |    3 | Using index |
|  1 | SIMPLE      | film       | eq_ref | PRIMARY           | PRIMARY           | 4       | test.film_acteur.film_id |    1 | NULL        |
+----+-------------+------------+--------+-------------------+-------------------+---------+---------------------------+------+-------------+

ref : Semblable à eq_ref mais utilise un index non unique ou un préfixe d'index unique. Plusieurs lignes peuvent correspondre.

-- 1. SELECT simple, nom est un index non unique
mysql> EXPLAIN SELECT * FROM film WHERE nom = 'film1';
+----+-------------+-------+------+---------------+----------+---------+-------+------+--------------------------+
| id | select_type | table | type | possible_keys | key      | key_len | ref   | rows | Extra                    |
+----+-------------+-------+------+---------------+----------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | film  | ref  | idx_nom       | idx_nom  | 33      | const |    1 | Using where; Using index |
+----+-------------+-------+------+---------------+----------+---------+-------+------+--------------------------+

-- 2. Jointure, idx_film_acteur_id est un index composite (film_id, acteur_id). Utilisation du préfixe film_id.
mysql> EXPLAIN SELECT * FROM film LEFT JOIN film_acteur ON film.identifiant = film_acteur.film_id;
+----+-------------+------------+-------+-------------------+-------------------+---------+------------------+------+-------------+
| id | select_type | table      | type  | possible_keys     | key               | key_len | ref              | rows | Extra       |
+----+-------------+------------+-------+-------------------+-------------------+---------+------------------+------+-------------+
|  1 | SIMPLE      | film       | index | NULL              | idx_nom           | 33      | NULL             |    3 | Using index |
|  1 | SIMPLE      | film_acteur | ref   | idx_film_acteur_id | idx_film_acteur_id | 4       | test.film.identifiant |    1 | Using index |
+----+-------------+------------+-------+-------------------+-------------------+---------+------------------+------+-------------+

ref_or_null : Similaire à ref mais peut également chercher les lignes avec NULL.

mysql> EXPLAIN SELECT * FROM film WHERE nom = 'film1' OR nom IS NULL;
+----+-------------+-------+-------------+---------------+----------+---------+-------+------+--------------------------+
| id | select_type | table | type        | possible_keys | key      | key_len | ref   | rows | Extra                    |
+----+-------------+-------+-------------+---------------+----------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | film  | ref_or_null | idx_nom       | idx_nom  | 33      | const |    2 | Using where; Using index |
+----+-------------+-------+-------------+---------------+----------+---------+-------+------+--------------------------+

index_merge : Utilise la fusion d'index (plusieurs index sont utilisés et leurs résultats sont fusionnés). Exemple : une condition OR sur la clé primaire et un autre index.

mysql> EXPLAIN SELECT * FROM role WHERE identifiant = 11011 OR tenant_id = 8888;
+----+-------------+-------+-------------+-----------------------+-----------------------+---------+------+------+-------------------------------------------------+
| id | select_type | table | type        | possible_keys         | key                   | key_len | ref  | rows | Extra                                           |
+----+-------------+-------+-------------+-----------------------+-----------------------+---------+------+------+-------------------------------------------------+
|  1 | SIMPLE      | role  | index_merge | PRIMARY,idx_tenant_id | PRIMARY,idx_tenant_id | 4,4     | NULL |  134 | Using union(PRIMARY,idx_tenant_id); Using where |
+----+-------------+-------+-------------+-----------------------+-----------------------+---------+------+------+-------------------------------------------------+

range : Balayage d'intervalle, généralement avec IN(), BETWEEN, >, <, >=, etc. Utilise un index pour récupérer les lignes dans l'intervalle.

mysql> EXPLAIN SELECT * FROM acteur WHERE identifiant > 1;
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | acteur | range | PRIMARY       | PRIMARY | 4       | NULL |    2 | Using where |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+

index : Similaire à ALL mais ne parcourt que l'arbre d'index (généralement plus rapide qu'un parcours complet de table).

mysql> EXPLAIN SELECT COUNT(*) FROM film;
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key      | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+
|  1 | SIMPLE      | film  | index | NULL          | idx_nom  | 33      | NULL |    3 | Using index |
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+

ALL : Parcours complet de la table. MySQL doit lire toutes les lignes pour trouver celles qui correspondent. En général, un index est nécessaire pour améliorer les performances.

mysql> EXPLAIN SELECT * FROM acteur;
+----+-------------+--------+------+---------------+------+---------+------+------+-------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | acteur | ALL  | NULL          | NULL | NULL    | NULL |    3 | NULL  |
+----+-------------+--------+------+---------------+------+---------+------+------+-------+

5. Colonne possible_keys

Montre les index que MySQL pourrait utiliser pour trouver les lignes. Si cette colonne contient des index mais que key est NULL, c'est souvent parce que la table contient peu de données et que MySQL juge l'index inutile. Si possible_keys est NULL, aucun index pertinent n'existe : examinez la clause WHERE pour créer un index approprié.

6. Colonne key

Indique l'index réellement utilisé par MySQL. Si NULL, aucun index n'a été utilisé. Vous pouvez forcer l'utilisation ou l'ignorance d'un index avec FORCE INDEX ou IGNORE INDEX.

7. Colonne key_len

Longueur (en octets) de l'index utilisé. Permet de connaître les colonnes exactes utilisées dans un index composite. Par exemple, dans film_acteur, l'index composite idx_film_acteur_id contient les colonnes film_id et acteur_id (de type INT, 4 octets chacun). Si key_len=4, seule la première colonne (film_id) est utilisée.

mysql> EXPLAIN SELECT * FROM film_acteur WHERE film_id = 2;
+----+-------------+------------+------+-------------------+-------------------+---------+-------+------+-------------+
| id | select_type | table      | type | possible_keys     | key               | key_len | ref   | rows | Extra       |
+----+-------------+------------+------+-------------------+-------------------+---------+-------+------+-------------+
|  1 | SIMPLE      | film_acteur | ref  | idx_film_acteur_id | idx_film_acteur_id | 4       | const |    1 | Using index |
+----+-------------+------------+------+-------------------+-------------------+---------+-------+------+-------------+

Règles de calcul de key_len :

  • Chaînes :
    • CHAR(n) : n octets
    • VARCHAR(n) : 2 octets pour la longueur + longueur réelle (ex. UTF-8 : 3n + 2)
  • Numériques :
    • TINYINT : 1 octet
    • SMALLINT : 2 octets
    • INT : 4 octets
    • BIGINT : 8 octets
  • Temporels :
    • DATE : 3 octets
    • TIMESTAMP : 4 octets
    • DATETIME : 8 octets
  • Si la colonne autorise NULL, 1 octet supplémentaire est ajouté.

La longueur maximale d'un index est de 768 octets. Pour les chaînes trop longues, MySQL utilise un préfixe (premiers caractères).

8. Colonne ref

Montre les colonnes ou constantes utilisées pour l'index indiqué dans key. Valeurs courantes : const (constante), func, NULL, ou un nom de colonne (ex. film.identifiant).

9. Colonne rows

Estimation du nombre de lignes que MySQL doit lire et vérifier. Ce n'est pas le nombre de lignes du résultat final.

10. Colonne Extra

Informations supplémentaires. Voici les plus importantes :

  • Distinct : MySQL arrête la recherche dès qu'il trouve une ligne correspondante (lié à DISTINCT).
mysql> EXPLAIN SELECT DISTINCT nom FROM film LEFT JOIN film_acteur ON film.identifiant = film_acteur.film_id;
+----+-------------+------------+-------+-------------------+-------------------+---------+------------------+------+------------------------------+
| id | select_type | table      | type  | possible_keys     | key               | key_len | ref              | rows | Extra                        |
+----+-------------+------------+-------+-------------------+-------------------+---------+------------------+------+------------------------------+
|  1 | SIMPLE      | film       | index | idx_nom           | idx_nom           | 33      | NULL             |    3 | Using index; Using temporary |
|  1 | SIMPLE      | film_acteur | ref   | idx_film_acteur_id | idx_film_acteur_id | 4       | test.film.identifiant |    1 | Using index; Distinct        |
+----+-------------+------------+-------+-------------------+-------------------+---------+------------------+------+------------------------------+
  • Using index : Les colonnes demandées sont toutes dans l'index (couverture d'index). MySQL n'a pas besoin d'accéder à la table. Bonne performence.
mysql> EXPLAIN SELECT identifiant FROM film ORDER BY identifiant;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | film  | index | NULL          | PRIMARY | 4       | NULL |    3 | Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
  • Using where : MySQL filtre les lignes après les avoir récupérées du moteur de stockage. Il lit chaque ligne, puis vérifie la condition WHERE.
mysql> EXPLAIN SELECT * FROM film WHERE identifiant > 1;
+----+-------------+-------+-------+---------------+----------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys | key      | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+---------------+----------+---------+------+------+--------------------------+
|  1 | SIMPLE      | film  | index | PRIMARY       | idx_nom  | 33      | NULL |    3 | Using where; Using index |
+----+-------------+-------+-------+---------------+----------+---------+------+------+--------------------------+
  • Using temporary : MySQL doit créer une table temporaire pour traiter la requête (ex. DISTINCT sans index). À optimiser en ajuotant un index.
-- Sans index sur acteur.nom
mysql> EXPLAIN SELECT DISTINCT nom FROM acteur;
+----+-------------+--------+------+---------------+------+---------+------+------+-----------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows | Extra           |
+----+-------------+--------+------+---------------+------+---------+------+------+-----------------+
|  1 | SIMPLE      | acteur | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using temporary |
+----+-------------+--------+------+---------------+------+---------+------+------+-----------------+

-- Avec index sur film.nom (idx_nom)
mysql> EXPLAIN SELECT DISTINCT nom FROM film;
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key      | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+
|  1 | SIMPLE      | film  | index | idx_nom       | idx_nom  | 33      | NULL |    3 | Using index |
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+
  • Using filesort : MySQL effectue un tri en externe (fichier temporaire) au lieu d'utiliser l'ordre de l'index. À optimiser en ajoutant un index approprié sur la colonne de tri.
-- Sans index sur acteur.nom
mysql> EXPLAIN SELECT * FROM acteur ORDER BY nom;
+----+-------------+--------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows | Extra          |
+----+-------------+--------+------+---------------+------+---------+------+------+----------------+
|  1 | SIMPLE      | acteur | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using filesort |
+----+-------------+--------+------+---------------+------+---------+------+------+----------------+

-- Avec index idx_nom sur film.nom
mysql> EXPLAIN SELECT * FROM film ORDER BY nom;
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key      | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+
|  1 | SIMPLE      | film  | index | NULL          | idx_nom  | 33      | NULL |    3 | Using index |
+----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+

Tables et données utilisées

Voici les instructions SQL de création et d'insertion des tables utilisées dans tous les exemples ci-dessus :

DROP TABLE IF EXISTS `acteur`;
CREATE TABLE `acteur` (
  `identifiant` int(11) NOT NULL,
  `nom` varchar(45) DEFAULT NULL,
  `date_maj` datetime DEFAULT NULL,
  PRIMARY KEY (`identifiant`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `acteur` (`identifiant`, `nom`, `date_maj`) VALUES
(1, 'a', '2017-12-22 15:27:18'),
(2, 'b', '2017-12-22 15:27:18'),
(3, 'c', '2017-12-22 15:27:18');

DROP TABLE IF EXISTS `film`;
CREATE TABLE `film` (
  `identifiant` int(11) NOT NULL AUTO_INCREMENT,
  `nom` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`identifiant`),
  KEY `idx_nom` (`nom`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `film` (`identifiant`, `nom`) VALUES
(3, 'film0'),
(1, 'film1'),
(2, 'film2');

DROP TABLE IF EXISTS `film_acteur`;
CREATE TABLE `film_acteur` (
  `identifiant` int(11) NOT NULL,
  `film_id` int(11) NOT NULL,
  `acteur_id` int(11) NOT NULL,
  PRIMARY KEY (`identifiant`),
  KEY `idx_film_acteur_id` (`film_id`,`acteur_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `film_acteur` (`identifiant`, `film_id`, `acteur_id`) VALUES
(1, 1, 1),
(2, 1, 2),
(3, 2, 1);

Références

Étiquettes: MySQL EXPLAIN optimisation de requêtes index base de données

Publié le 2 juin à 17h59