Cette requête s'exécute plus de 12 secondes, même si toutes les tables sont relativement petites (environ 2 000 lignes).Comment optimiser la jointure qui entraîne une performance très lente
SELECT attr_73206_ AS attr_73270_
FROM object_73130_ f1
LEFT OUTER JOIN (
SELECT id_field, attr_73206_ FROM (
SELECT m.id_field, t0.attr_73102_ AS attr_73206_ FROM object_73200_ o
INNER JOIN master_slave m ON (m.id_object = 73130 OR m.id_object = 73290) AND (m.id_master = 73200 OR m.id_master = 73354) AND m.id_slave_field = o.id
INNER JOIN object_73101_ t0 ON t0.id = o.attr_73206_
ORDER BY o.id_order
) AS o GROUP BY o.id_field
) AS o ON f1.id = o.id_field
Les deux tables ont des champs id
comme clés primaires. En outre, id_field
, id_order
, attr_73206_
et tous les champs de master_slave
sont indexés. Quant à la logique de cette requête, elle est globalement de type master-detail. Le tableau object_73130_
est une table principale, la table object_73200_
est une table de détail. Ils sont liés par une table master_slave
. object_73101_
est une table ad hoc utilisée pour obtenir une valeur réelle pour le champ attr_73206_
par son identifiant. Pour chaque ligne de la table principale, la requête renvoie un champ de la toute première ligne de sa table de détail. Tout d'abord, la requête avait un autre aspect, mais ici, chez stackoverflow, il m'a été conseillé d'utiliser cette structure plus optimisée (au lieu d'une sous-requête utilisée auparavant, et, par ailleurs, la requête a démarré beaucoup plus vite). J'observe que la sous-requête dans le premier bloc JOIN
s'exécute très rapidement mais renvoie un nombre de lignes comparable au nombre de lignes dans la table principale principale. De toute façon, je ne sais pas comment l'optimiser. Je me demande simplement pourquoi une simple jointure rapide cause beaucoup de problèmes. Oh, l'observation principale est que si je supprime un object_73101_
ad-hoc de la requête pour retourner juste un ID, mais pas une valeur réelle, alors la requête s'exécute aussi rapidement qu'un flash. Donc, toute l'attention devrait être concentrée sur cette partie de la requête
INNER JOIN object_73101_ t0 ON t0.id = o.attr_73206_
Pourquoi ralentit-il si terriblement toute la requête?
EDIT
De cette façon, il fonctionne super rapide
SELECT t0.attr_73102_ AS attr_73270_
FROM object_73130_ f1
LEFT OUTER JOIN (
SELECT id_field, attr_73206_ FROM (
SELECT m.id_field, attr_73206_ FROM object_73200_ o
INNER JOIN master_slave m ON (m.id_object = 73130 OR m.id_object = 73290) AND (m.id_master = 73200 OR m.id_master = 73354) AND m.id_slave_field = o.id
ORDER BY o.id_order
) AS o GROUP BY o.id_field
) AS o ON f1.id = o.id_field
LEFT JOIN object_73101_ t0 ON t0.id = o.attr_73206_
Ainsi, vous pouvez voir, que je viens de mettre le add-hoc se joindre à l'extérieur de la sous-requête. Mais, le problème est, cette sous-requête est automatiquement créée et j'ai un accès à cette partie de l'algo qui la crée et je peux modifier cet algo, et je n'ai pas accès à la partie d'algo qui construit la requête entière, donc le La seule chose que je peux faire est juste de réparer la sous-requête en quelque sorte. Quoi qu'il en soit, je n'arrive toujours pas à comprendre pourquoi INNER JOIN
dans une sous-requête peut ralentir l'ensemble de la requête des centaines de fois.
EDIT
Une nouvelle version de requête avec différents alias pour chaque table. Cela n'a aucun effet sur les performances:
SELECT attr_73206_ AS attr_73270_
FROM object_73130_ f1
LEFT OUTER JOIN (
SELECT id_field, attr_73206_ FROM (
SELECT m.id_field, t0.attr_73102_ AS attr_73206_ FROM object_73200_ a
INNER JOIN master_slave m ON (m.id_object = 73130 OR m.id_object = 73290) AND (m.id_master = 73200 OR m.id_master = 73354) AND m.id_slave_field = a.id
INNER JOIN object_73101_ t0 ON t0.id = a.attr_73206_
ORDER BY a.id_order
) AS b GROUP BY b.id_field
) AS c ON f1.id = c.id_field
EDIT
Ceci est le résultat de EXPLAIN
commande:
| id | select_type | TABLE | TYPE | possible_keys | KEY | key_len | ROWS | Extra |
| 1 | PRIMARY | f1 | INDEX | NULL | PRIMARY | 4 | 1570 | USING INDEX
| 1 | PRIMARY | derived2| ALL | NULL | NULL | NULL | 1564 |
| 2 | DERIVED | derived3| ALL | NULL | NULL | NULL | 1575 | USING TEMPORARY; USING filesort
| 3 | DERIVED | m | RANGE | id_object,id_master,..| id_object | 4 | 1356 | USING WHERE; USING TEMPORARY; USING filesort
| 3 | DERIVED | a | eq_ref | PRIMARY,attr_73206_ | PRIMARY | 4 | 1 |
| 3 | DERIVED | t0 | eq_ref | PRIMARY | PRIMARY | 4 | 1 |
Quel est le problème avec ça?
EDIT
Voici le résultat de la commande EXPLAIN
pour la "super-rapide" requête
| id | select_type | TABLE | TYPE | possible_keys | KEY | key_len | ROWS | Extra
| 1 | PRIMARY | f1 | INDEX | NULL | PRIMARY | 4 | 1570 | USING INDEX
| 1 | PRIMARY | derived2| ALL | NULL | NULL | NULL | 1570 |
| 1 | PRIMARY | t0 | eq_ref| PRIMARY | PRIMARY | 4 | 1 |
| 2 | DERIVED | derived3| ALL | NULL | NULL | NULL | 1581 | USING TEMPORARY; USING filesort
| 3 | DERIVED | m | RANGE | id_object,id_master,| id_bject | 4 | 1356 | USING WHERE; USING TEMPORARY; USING filesort
| 3 | DERIVED | a | eq_ref | PRIMARY | PRIMARY | 4 | 1 |
FERME
je vais utiliser mon propre "ultra-rapide" requête, que j'ai présenté ci-dessus. Je pense qu'il est impossible de l'optimiser plus.
. . Votre utilisation du 'order by' dans la sous-requête avant la jointure est hautement suspecte. MySQL ne garantit pas explicitement quelles valeurs seront retournées lorsque vous utiliserez un champ non mentionné dans la clause 'group by' (voir http://dev.mysql.com/doc/refman/5.5/fr/group-by-extensions). html). –
Avez-vous utilisé la fonctionnalité [** EXPLAIN **] (http://dev.mysql.com/doc/refman/5.7/fr/using-explain.html)? –
Si j'enlève ORDER BY a.id_order, cela n'a toujours aucun effet. Comme je l'ai dit, tout le problème est dans l'INNER JOIN object_73101_ etc Événement bien qu'il ne ralentisse pas la sous-requête elle-même, il ralentit terriblement toute la requête – Jacobian