0

Je cherche à optimiser la requête MySQL ci-dessous. Y a-t-il un index multi-colonnes qui aurait plus de succès? J'ai essayé (created_date, rep_id) sans chance. Toutes les suggestions pour accélérer cette requête sont appréciées.Optimisation de la requête MySQL avec plage et jointures multiples

SELECT 
customer.rep_id AS `ID`, 
COUNT(*) AS Count, 
rep.first_name, 
rep.last_name 

FROM customer 
INNER JOIN appointment ON customer.id = appointment.customer_id 
INNER JOIN rep ON customer.rep_id = rep.user_id 
INNER JOIN user ON rep.user_id = user.id 

WHERE customer.rep_id != 0 
AND customer.saved = 0 
AND customer.deleted = 0 
AND customer.created_date >= '2017-01-01' 
AND customer.created_date < '2017-02-01' 
AND appointment.current = 1 
AND appointment.realStatus IS NOT NULL 
AND ( appointment.realStatus not in('rescheduled','cancelled') 
    OR (appointment.closed_by_id IS NULL 
    OR customer.rep_id != appointment.closed_by_id) 
    ) 
AND user.knocks = 1 
AND user.deleted = 0 
GROUP BY customer.rep_id 
ORDER BY `Count` DESC 
LIMIT 50 

est ici la sortie EXPLAIN:

id: 1 
select_type: SIMPLE 
table: customer 
type: range 
possible_keys: PRIMARY,rep_id,created_date 
key: NULL 
key_len: NULL 
ref: NULL 
rows: 354846 
Extra: Using where; Using temporary; Using filesort 

id: 1 
select_type: SIMPLE 
table: rep 
type: ref 
possible_keys: user_id 
key: user_id 
key_len: 4 
ref: customer.rep_id 
rows: 1 
Extra: Using index condition 

id: 1 
select_type: SIMPLE 
table: user 
type: eq_ref 
possible_keys: PRIMARY 
key: PRIMARY 
key_len: 4 
ref: rep.user_id 
rows: 1 
Extra: Using where 

id: 1 
select_type: SIMPLE 
table: appointment 
type: ref 
possible_keys: realStatus, customer_id, created_date 
key: customer_id 
key_len: 4 
ref: customer.id 
rows: 1 
Extra: Using where 
+0

Avez-vous essayé d'utiliser entre pour la plage de dates? Je ne sais pas si cela le ferait commencer à utiliser l'index ou non, mais ça vaut le coup d'essayer. –

+0

Si vous utilisez une plage de dates pour un mois civil, un index sur l'année-mois uniquement de customer.created_date autoriserait un nombre calculé au lieu d'une plage pour la requête mensuelle. –

+0

Est-ce que rep est une vue de contact? – ysth

Répondre

0

légèrement réécrite de requête pour une meilleure lisibilité et d'association visuelle à d'autres tables dans la jointure ..

SELECT 
     customer.rep_id AS `ID`, 
     COUNT(*) AS Count, 
     rep.first_name, 
     rep.last_name 
    FROM 
     customer 
      INNER JOIN appointment 
       ON customer.id = appointment.customer_id 
       AND appointment.current = 1 
       AND appointment.realStatus IS NOT NULL 
      INNER JOIN rep 
       ON customer.rep_id = rep.user_id 
       INNER JOIN user 
        ON rep.user_id = user.id 
        AND user.knocks = 1 
        AND user.deleted = 0 
    WHERE 
      customer.rep_id != 0 
     AND customer.saved = 0 
     AND customer.deleted = 0 
     AND customer.created_date >= '2017-01-01' 
     AND customer.created_date < '2017-02-01' 
     AND (appointment.realStatus not in('rescheduled','cancelled') 
      OR ( appointment.closed_by_id IS NULL 
       OR customer.rep_id != appointment.closed_by_id)) 
    GROUP BY 
     customer.rep_id 
    ORDER BY 
     `Count` DESC 
    LIMIT 
     50 

Vous avez probablement besoin de plusieurs indices composites pour aider à la requête. De plus, j'ai déplacé certains des éléments de la requête pour mieux correspondre à l'application des critères (tels que le rendez-vous et l'utilisateur). Cela aide également à identifier une meilleure option d'index. Cela dit, je voudrais offrir les index suivants sur chaque

table  index 
customer  (saved, deleted, created_date, rep_id) 
rep   (user_id) 
appointment (customer_id, current, realStatus) 
+0

Merci! Cela fonctionne très bien.J'ai un index (rep_id, saved, deleted, created_date) qui n'est pas aussi efficace dans la sortie EXPLAIN, mais s'exécute à peu près en même temps et fonctionne avec beaucoup plus de mes requêtes. Pouvez-vous m'expliquer l'ordre de l'index? Nouveau à ce truc d'optimisation :) –

+1

@ b.dig, jetez un oeil à ces https://stackoverflow.com/questions/27658786/optimizing-a-very-huge-mysql-table-query-or-mysql/27659098# 27659098 et laissez-moi savoir si cela vous aide à comprendre le contexte. Les index doivent correspondre aux critères WHERE ou JOIN primaires dans le contexte des enregistrements optimisés (par exemple, l'autre lien décrit). – DRapp

+0

[_More on indexing_] (http://mysql.rjweb.org/doc.php/index_cookbook_mysql), y compris pourquoi avoir 'saved' et' deleted' d'abord (en raison de '=') et 'rep_id' en dernier (pour "couvrant"). –

0

Ajouter un indicateur d'index: from customer use index (created_date) inner join ...

(Notez que use index ne fait pas ce qu'il dit, il est tout simplement l'optimiseur ignorer les index vous ne mentionnez pas.)

Autre que cela, en rendant l'index customer_id de rendez-vous sur (customer_id,current) pourrait aider.

+0

Forcé l'index created_date et il n'accélère pas autant que j'espérais. Je suis novice en optimisation ... y a-t-il un index multi-colonnes qui fonctionnerait mieux? –

+0

Est-ce qu'expliquer maintenant le montrer en utilisant un index pour le client? – ysth

+0

Oui, cependant, il ne fonctionne pas plus vite. Voici la mise à jour EXPLAIN pour la table client: 1, SIMPLE, client, plage, date_départ, date_définie, 6, 115032, Utilisation de la condition d'index; En utilisant où; En utilisant temporaire; Utilisation de fichiersort –

0

Vous avez probablement besoin d'un indice composé - quelque chose comme:

créer un index sur plusieurs clients (id, rep_id, CREATED_DATE); MySQL utilise un seul index pour chaque table (selon la version, le moteur, etc.), et s'il pense que les index existants ne seront pas utiles, il peut les ignorer.

Je suppose que client.saved et customer.deleted sont deux colonnes avec peu de valeurs possibles - oui/non, 0/1 etc. Ils ont tendance à être ignorés par les moteurs d'optimisation de requête.

+0

Il est presque toujours inutile de démarrer un index composite avec la 'PRIMARY KEY'. Un index sur _only_ un "indicateur" ne sera généralement pas utilisé, mais un index _composite_ qui inclut un indicateur suit des règles différentes. –