Mysql
 sql >> Base de données >  >> RDS >> Mysql

Requête lente MySQL :JOIN + plusieurs WHERES + ORDER BY

Les indices font une énorme différence dans mysql, une requête qui a pris 15 minutes avec un mauvais ensemble d'indices a pris 0,2 seconde avec les bons, mais c'est généralement le problème de trouver le bon équilibre. Naturellement, sans quelques exemples de données, il est vraiment difficile de dire si la solution ci-dessous vous fera gagner du temps, mais en théorie, elle le devrait.

Pour répondre à vos questions, je remanierais les tableaux comme suit :

CREATE TABLE `product_all` ( 
`prod_id` INT( 10 ) NOT NULL, 
`ref_id` INT( 10) NOT NULL, 
`date` DATE NOT NULL , 
`buy_link` BLOB NOT NULL , 
`sale_price` FLOAT NOT NULL,
PRIMARY KEY (prod_id, ref_id) ,
INDEX date_Index (`date` ASC),
UNIQUE INDEX prod_price_Index (prod_id ASC, sale_price ASC)
) ENGINE = MYISAM ; 


CREATE TABLE `product_info` ( 
`prod_id` INT( 10 ) NOT NULL AUTO_INCREMENT, 
`prod_name` VARCHAR( 200 ) NOT NULL, 
`brand` VARCHAR( 50 ) NOT NULL, 
`retail_price` FLOAT NOT NULL, 
`category` INT( 3 ) NOT NULL, 
`gender` VARCHAR( 1 ) NOT NULL, 
`type` VARCHAR( 10 ) NOT NULL,
PRIMARY KEY (prod_id) ,
UNIQUE INDEX prod_id_name_Index (prod_id ASC, prod_name ASC),
INDEX category_Index (category ASC),
INDEX gender_Index (gender ASC)
) ENGINE = MYISAM ;

SELECT product_info.*, MIN(product_all.sale_price) as sale_price, product_all.buy_link         
FROM product_info         
NATURAL JOIN (SELECT * FROM product_all WHERE product_all.date = '2010-09-30') as product_all         
WHERE (product_info.category = 2           
AND product_info.gender = 'W' )         
GROUP BY product_all.prod_id         
ORDER BY MIN(product_all.sale_price) ASC LIMIT 13        

Le gain de performance ici est obtenu en indexant les principaux champs qui sont joints et qui sont présentés dans la clause where. Personnellement, j'irais avec votre première requête car lorsque vous y réfléchissez, cela devrait mieux fonctionner.

Pour autant que je comprenne ce qui se passe dans la première et la deuxième requête :

  • La première requête est filtrée par une sous-requête avant d'effectuer la jointure naturelle, c'est-à-dire sa seule jointure dans les données résultantes et non dans l'ensemble de la table.
  • La deuxième requête consiste à joindre l'intégralité de la deuxième table, puis à filtrer les lignes résultantes de l'ensemble du lot en fonction de ce que vous voulez.

En règle générale, vous souhaitez normalement ajouter des index sur vos principaux champs de jointure ainsi que sur les champs que vous utilisez le plus dans les clauses where. J'ai également mis des index uniques sur certains des champs que vous souhaiterez interroger régulièrement, tels que prod_id_name_Index.

Si cela n'améliore pas vos performances, si vous pouviez peut-être publier des données factices avec lesquelles jouer, je pourrais peut-être obtenir une solution plus rapide que je pourrais comparer.

ici est un article qui passe par l'indexation des performances dans mysql, mérite d'être lu si vous voulez en savoir plus.

Bonne chance !

EDIT:Votre dernière question que j'ai manquée la première fois, la réponse est que si votre indexation des principaux champs de jointure passe ensuite à l'où n'aura qu'un léger impact sur les performances globales, mais les indices uniques que j'ai mis sur les tables devraient tenir compte de la majorité des éléments sur lesquels vous souhaiterez baser vos requêtes. La principale chose à retenir est que si vous interrogez ou rejoignez fréquemment un champ, il doit vraiment être indexé, mais les requêtes mineures et les modifications de l'ordre que vous faites ne devraient tout simplement pas vous inquiéter en termes de réalignement de votre stratégie d'indexation.