2017-08-05 1 views
0

Lorsque je vérifie SHOW PROCESSLIST; dans la base de données, j'ai eu une requête ci-dessous. Il utilise beaucoup de CPU (plus de 100%), il a fallu 80 secondes pour terminer la requête. Nous avons un serveur séparé pour la base de données (64GB RAM).requête lente avec beaucoup de jointures à gauche

INSERT INTO `search_tmp_598075de5c7e67_73335919` 
SELECT `main_select`.`entity_id`, MAX(score) AS `relevance` 
    FROM (SELECT `search_index`.`entity_id`, (((0)) * 1) AS score 
     FROM `catalogsearch_fulltext_scope1` AS `search_index` 
     LEFT JOIN `catalog_eav_attribute` AS `cea` 
        ON search_index.attribute_id = cea.attribute_id 
     LEFT JOIN `catalog_category_product_index` AS `category_ids_index` 
        ON search_index.entity_id = category_ids_index.product_id 
     LEFT JOIN `review_entity_summary` AS `rating` 
        ON `rating`.`entity_pk_value`=`search_index`.entity_id 
        AND `rating`.entity_type = 1 
        AND `rating`.store_id = 1 
     WHERE (category_ids_index.category_id = 2299) 
) AS `main_select` 
GROUP BY `entity_id` 
ORDER BY `relevance` DESC 
LIMIT 10000 

Pourquoi cette requête utilise-t-elle mes ressources CPU complètes?

+0

Mauvais ou ne pas indexer dans la partie SELECT peut-être nous avons besoin de voir une explication de la partie de sélection. –

+0

Quelles sont les clés primaires de vos tables? – trincot

+0

Ceci est un exemple à quoi les requêtes ne devraient pas ressembler. –

Répondre

3

Quelques inefficacités:

  • Il y a une condition non nulle sur les registres de l'extérieur se sont joints catalog_category_product_index. Cela transforme la jointure externe en une jointure interne. Il sera plus efficace d'utiliser une clause inner join.

  • Il n'est pas nécessaire d'avoir une requête imbriquée: le regroupement, la commande et la limitation peuvent être effectués directement sur la requête interne.

  • (((0)) * 1) est juste une façon de dire complexe 0, et en prenant la MAX de qui renverra évidemment encore une pertinence de 0 pour tous les enregistrements. Non seulement c'est un moyen inefficace de sortir 0, mais cela n'a aucun sens non plus. Je suppose que votre requête réelle a un calcul moins évident, ce qui pourrait nécessiter une optimisation.

  • Si catalog_eav_attribute.attribute_id est un champ unique, alors il n'y a aucun sens à extérieur se joindre à cette table, parce que les données ne sont pas utilisées partout

  • Si review_entity_summary.entity_pk_value est unique (au moins quand entity_type = 1 et store_id = 1), puis de nouveau Si les champs des points 2 ci-dessus ne sont pas uniques, le nombre d'enregistrements renvoyés par valeur search_index.entity_id n'influence pas le résultat. (comme il se tient actuellement avec l'obscur (((0)) * 1) valeur, ce n'est pas le cas), alors aucune jointure externe n'est nécessaire non plus.

Avec ces hypothèses, la select partie peut être réduite à:

SELECT  search_index.entity_id, 
      MAX(((0)) * 1) AS relevance 
FROM  catalogsearch_fulltext_scope1 AS search_index 
INNER JOIN catalog_category_product_index AS category_ids_index 
     ON search_index.entity_id = category_ids_index.product_id 
WHERE  category_ids_index.category_id = 2299 
GROUP BY search_index.entity_id 
ORDER BY relevance DESC 
LIMIT  10000 

je encore quitté la (((0)) * 1) là-dedans, mais il n'a vraiment aucun sens.