|   | |||||||||||||||||||||||||||||||
|     | |||||||||||||||||||||||||||||||
|  |  7.21   | ||||||||||||||||||||||||||||||
| Table | Column | Column type | 
| tt | ActualPC | CHAR(10) | 
| tt | AssignedPC | CHAR(10) | 
| tt | ClientID | CHAR(10) | 
| et | EMPLOYID | CHAR(15) | 
| do | CUSTNMBR | CHAR(15) | 
| Table | Index | 
| tt | ActualPC | 
| tt | AssignedPC | 
| tt | ClientID | 
| et | EMPLOYID(primary key) | 
| do | CUSTNMBR(primary key) | 
tt.ActualPC n'ont pas encore été assignées.
Au démarrage, avant la moindre optimisation, la clause produit la réponse suivante :
table type possible_keys                key  key_len ref  rows  Extra
et    ALL  PRIMARY                      NULL NULL    NULL 74
do    ALL  PRIMARY                      NULL NULL    NULL 2135
et_1  ALL  PRIMARY                      NULL NULL    NULL 74
tt    ALL  AssignedPC,ClientID,ActualPC NULL NULL    NULL 3872
      range checked for each record (key map: 35)
Etant donné que le type de regroupement est ALL pour toutes les tables, ces informations indique que MySQLfait un regroupement sur toutes les tables! Cela va prendre un temps énorme, vu le nombre de lignes à étudier dans chaque table. Pour le cas présent, cela représente 74 * 2135 * 74 * 3872 = 45,268,558,720 rows. Et encore, ces tables pourraient être encore plus grosses...
Un des problèmes posés ici est que MySQL ne peut pas encore (encore) utiliser d'index pour des colonnes déclarées de manière différentes. Dans l'exemple, VARCHAR et CHAR sont identiques, à moins qu'ils ne soient déclarés sur des longueurs différentes. Or, tt.ActualPC est de type CHAR(10) et et.EMPLOYID est de type CHAR(15) : les longueur ne concordent pas.
Pour consolider la base, on utilise la commande ALTER TABLE pour rallonger le champs ActualPC de 10 caractères à 15 caractères:
mysql> ALTER TABLE tt MODIFY ActualPC VARCHAR(15);
Maintenant, tt.ActualPC et et.EMPLOYID sont tous les deux de type VARCHAR(15). L'éxecution de la commande EXPLAIN produit maintenant le résultat suivant :
table type   possible_keys   key     key_len ref         rows    Extra
tt    ALL    AssignedPC,ClientID,ActualPC NULL NULL NULL 3872    where used
do    ALL    PRIMARY         NULL    NULL    NULL        2135
      range checked for each record (key map: 1)
et_1  ALL    PRIMARY         NULL    NULL    NULL        74
      range checked for each record (key map: 1)
et    eq_ref PRIMARY         PRIMARY 15      tt.ActualPC 1
Ce n'est pas parfait, mais c'est nettement mieux (le produit des colonnes rows a été réduit d'un facteur 74). Cette version s'éxecute maintenant en quelques secondes.
Une autre amélioration peut être apportée en éliminant les disparités de longueur entre les colonnes tt.AssignedPC et et_1.EMPLOYID, et d'autres part , tt.ClientID et do.CUSTNMBR comparisons:
mysql> ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),
                      MODIFY ClientID   VARCHAR(15);
Maintenant EXPLAIN produit maintenant le résultat suivant :
table type possible_keys key key_len ref rows Extra et ALL PRIMARY NULL NULL NULL 74 tt ref AssignedPC,ClientID,ActualPC ActualPC 15 et.EMPLOYID 52 where used et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1 do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
C'est déjà très bien.
Le problème final est que, par défaut, MySQL suppose que les valeurs dans la colonne tt.ActualPC sont réparties uniformément. Or, ce n'est pas le cas de la table tt. Heureusement, il est facile de le préciser à MySQL :
shell> isamchk --analyze PATH_TO_MYSQL_DATABASE/tt shell> mysqladmin refresh
Le résultat est maintenant parfait, et maintenant EXPLAIN produit maintenant le résultat suivant :
table type possible_keys key key_len ref rows Extra tt ALL AssignedPC,ClientID,ActualPC NULL NULL NULL 3872 where used et eq_ref PRIMARY PRIMARY 15 tt.ActualPC 1 et_1 eq_ref PRIMARY PRIMARY 15 tt.AssignedPC 1 do eq_ref PRIMARY PRIMARY 15 tt.ClientID 1
On peut noter que la colonne rows est une estimation de la part de l'optimisateur de regroupement de MySQL : pour optimiser une commande, il faudrait maintenant vérifier qu'elle a des chiffres proche de la vérité. Si non, il faudrait améliorer les performances avec la clause STRAIGHT_JOIN dans la commande SELECT, et essayer de proposer différents ordres pour la liste des tables .