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 .