requête pour ce que les clients ont acheté avec le produit énuméré
Question
Je suis en train d'obtenir optimize une requête très ancienne que je ne peux pas envelopper ma tête. le résultat que je veux archive est que je veux recommander le visiteur sur une boutique en ligne ce que les autres clients ont manifesté leur intérêt, à savoir ce que les autres qu'ils ont acheté avec le produit que le visiteur regarde.
J'ai une sous-requête, mais il est très lent, prend ~ 15s sur ~ 8 000 000 lignes.
la mise en page est que tous les produits qui sont mis dans un panier utilisateurs sont conservés dans un wsBasket
de table et séparés par un basketid
(qui, dans une autre table est associée à un membre).
dans cet exemple que je veux la liste de tous les produits les plus populaires que les utilisateurs ont achetés ensemble avec ProductID 427, mais pas la liste le ProductID lui-même 427.
SELECT productid, SUM(quantity) AS qty
FROM wsBasket
WHERE basketid IN
(SELECT basketid
FROM wsBasket
WHERE productid=427) AND productid!=427
GROUP by productid
ORDER BY qty
DESC LIMIT 0,4;
toute aide est très appréciée! espérons que cela a un sens tout au moins une personne:)
UPDATE 1: Merci pour vos commentaires gars voici mes réponses, ils ne correspondaient pas aux commentaires sur le terrain.
Utilisation EXPLIQUEZ sur la requête ci-dessus je suis le fllowing. S'il vous plaît noter, je n'ai pas d'index sur la table (à l'exception de clé primaire sur le id
champ), je veux modifier la requête pour bénéficier des indices et des indices de place sur les touches droite.
+----+--------------------+----------+------+---------------+------+---------+------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+----------+------+---------------+------+---------+------+------+----------------------------------------------+
| 1 | PRIMARY | wsBasket | ALL | NULL | NULL | NULL | NULL | 2821 | Using where; Using temporary; Using filesort |
| 2 | DEPENDENT SUBQUERY | wsBasket | ALL | NULL | NULL | NULL | NULL | 2821 | Using where |
+----+--------------------+----------+------+---------------+------+---------+------+------+----------------------------------------------+
La solution
Deux indices évidents d'ajouter: un sur basketid et une seconde sur ProductID: puis retenter la requête et une nouvelle EXPLIQUER pour voir que les index sont utilisés
Autres conseils
En plus d'assurer que les indices appropriés existent sur productid
et basketid
, vous souvent bénéficier de la structuration de votre requête comme une simple jointure plutôt qu'un sous-requête, en particulier dans MySQL.
SELECT b1.productid, SUM(b1.quantity) AS qty
FROM wsBasket AS b0
JOIN wsBasket AS b1 ON b1.basketid=b0.basketid
WHERE b0.productid=427 AND b1.productid<>427
GROUP BY b1.productid
ORDER BY qty DESC
LIMIT 4
Pour moi, sur un ensemble de données peut-similaire, le join a donné lieu à deux rangées de select_type: SIMPLE
dans la sortie EXPLAIN
, alors que la méthode a craché une sous-requête DEPENDENT SUBQUERY
horrible en fonction des résultats. Par conséquent, la jointure était bien plus d'un ordre de grandeur plus rapide.
Les deux champs que vous utilisez principalement pour la recherche dans cette requête sont ProductID et basketid.
Lorsque vous recherchez des enregistrements ayant ProductID égal à 427, la base de données n'a pas la moindre idée où trouver cet enregistrement. Il ne sait même pas que si elle ne trouve une correspondance, qu'il n'y aura pas un autre correspondant, il doit regarder à travers toute la table, potentiellement des milliers d'enregistrements.
Un index est un fichier séparé qui est triée, et ne contient que le champ / s vous êtes intéressé par le tri sur. créant ainsi un indice permet d'économiser une quantité énorme de temps!