2012-08-30 1 views
3

J'ai 4 tables: expéditions (200K enregistrements), magasins (45 enregistrements), magasins_produits (enregistrements 8K), districts (698 enregistrements). La requête suivante prend très longtemps à excute (12 secondes):Les performances de la requête Mysql sont lentes, besoin d'aide pour l'optimisation.

SELECT `s`. * , `p`.`productCode` , `p`.`productName` , `st`.`name` AS `storeName` , `d`.`name` AS `districtName` 
FROM `shipments` AS `s` 
JOIN `product_stores` AS `p` ON s.productStoreId = p.id 
JOIN `stores` AS `st` ON s.storeId = st.id 
LEFT JOIN `districts` AS `d` ON s.districtId = d.id 
WHERE (s.storeId IN (1, 2, 3, 4, 6, 9, 14, 16, 22, 26, 30)) 
GROUP BY `s`.`id` 
ORDER BY `s`.`id` DESC 
LIMIT 100 

requête EXPLIQUEZ le résultat suivant:

id select_type  table type possible_keys key  key_len  ref  rows Extra 
1 SIMPLE st ALL  PRIMARY  NULL NULL NULL 45 Using where; Using temporary; Using filesort 
1 SIMPLE s ref  fk_shipments_stores1_idx,fk_shipments_product_stor... fk_shipments_stores1_idx 4 st.id 482  
1 SIMPLE p eq_ref PRIMARY  PRIMARY  4 s.productStoreId 1 
1 SIMPLE d eq_ref PRIMARY  PRIMARY  4 s.districtId 1 
  1. Je ne sais pas pourquoi MySQL doit l'aide temporaire; Utilisation de filesort dans ce cas
  2. Pourquoi mysql ne commence pas à sélectionner des envois? puis rejoignez le magasin. il commence à sélectionner à partir du magasin, puis rejoindre les envois? J'essaie d'exécuter EXPLAIN et parfois mysql commencer à sélectionner de la table product_stores
  3. S'il vous plaît aidez-moi à optimiser la table, les index ... pour améliorer les performances.

(J'utilise MySQL 5.0.95)

Ce sont les structures de table:

+0

Veuillez remplacer l'en-tête de votre question par quelque chose d'utile. –

Répondre

0

Je viens d'essayer la solution. Espérons que cela devrait réduire le temps d'exécution

SELECT `s`. * , `ps`.`productCode` , `ps`.`productName` , `st`.`name` AS `storeName` , `d`.`name` AS `shipToDistrictName` 
FROM `shipments` AS `s` 
JOIN `product_stores` AS `ps` ON s.productStoreId = ps.id 
JOIN `stores` AS `st` ON (s.storeId = st.id AND s.storeId IN (1, 2, 3, 4, 6, 9, 14, 16, 22, 26, 30)) 
LEFT JOIN `districts` AS `d` ON s.shipToDistrictId = d.id 
GROUP BY `s`.`id` 
ORDER BY `s`.`id` DESC 
LIMIT 100 

Cela limitera nombre d'enregistrements à seulement ceux ayant storeId que ceux qui sont nécessaires et encore faire se joignent au nombre réduit de dossiers, réduire ainsi le temps d'exécution.

Hope it helps ...

+0

J'ai essayé cela mais encore 12 -> 14 secondes – Kevin

1

votre requête sera assez lente parce que votre stratégie se joindre à la requête prendre trop d'E/S

Permettez-moi de calculer pour votre rédige requête E/S pour la compréhension de la manière suivante:

1. JOIN shipments (200K records) and product_stores (8K records) 

     200K x 8 K = 1600K I/O 
2. Then, JOIN to stores (45 records) 

     1600K x 45 = 75000K I/O 

3. Then, JOIN to districts (698 records) 

     75000K x 698 = 50256000K I/O 

4. Then, Filter the result (by storeId), so need to read the result I/O again 

     50256000K + 50256000K = **100512000K I/O (TOTAL I/O)** 

So, total I/O on memory of your query is 100512000K I/O. 

pour améliorer les performances de votre requête, vous devez reconsidérer votre plan se joindre à la requête/stratégie

par exemple:

1. Read shipments (200K records) and Filter storeId (assume: result is 8 record) 

     200K + 8 = 208K I/O 
2. Then, JOIN to product_stores (8K records) 

     208K x 8K = 1664K I/O 

3. Then, JOIN to stores (45 records) 

     1664K x 45K = 74880K I/O 

4. Then, finally JOIN to districts (698 records). 

     74880K + 698 = **52266240 I/O (TOTAL I/O)** 

So, total I/O on memory of your query is 52266240 I/O. (greatly reduce I/O then ever) 

Ainsi, vous pouvez améliorer les performances de votre requête par-dessus l'examen.

J'espère que cela peut vous aider.

+0

Merci beaucoup. J'ai changé l'INNER JOIN à LEFT JOIN, et maintenant seulement 0.003sec: SELECT 's'. *, 'ps'.'productCode',' ps'.'productName', 'st'.'name' AS' storeName', 'd'.'name' AS' shipToDistrictName' FROM 'expéditions'' AS' s' LEFT JOIN 'product_stores' AS' ps' ON ​​s.productStoreId = ps.id LEFT JOIN 'stores' AS' st' ON (s.storeId = st.id ET st.id IN (1, 2, 3, 4 , 6, 9, 14, 16, 22, 26, 30)) LEFT JOIN 'districts' AS' d' ON s.shipToDistrictId = d.id GROUPE BY 's'.'id' ORDER BY' s' .'id' DESC LIMIT 100 – Kevin

+0

Vous êtes les bienvenus – AKZap

Questions connexes