Wakizashi Wakizashi - 1 month ago 20
MySQL Question

Related products approach suggestion, MySQL InnoDB/PHP

I want to expand UI on my CodeIgniter shop with suggestions on what other people bought with the current product (either when viewing product or when product is put in the cart, irrelevant now for the question).
I have came up with this query (orders table contains order details, while order items contains products that are in specific order via foreign key, prd alias is for products table where all important info about prduct is stored).
Query looks like this

SELECT
pr.product_id,
COUNT(*) AS num,
prd.*
FROM
orders AS o
INNER JOIN order_items AS po ON o.id = po.order_id
INNER JOIN order_items AS pr ON o.id = pr.order_id
INNER JOIN products AS prd ON pr.product_id = prd.id
WHERE
po.product_id = '14211'
AND pr.product_id <> '14211'
GROUP BY
pr.product_id
ORDER BY
num DESC
LIMIT 3


It works nice and dandy, query time is 0.030ish seconds and it returns the products that bought together with the one I am currently viewing.

As for the questions and considerations, Percona query analyzer complains about this two things, Non-deterministic GROUP BY and GROUP BY or ORDER BY on different tables, which both I need so that I can get items on top that are actually relevant for the related query, but absolutely have no idea how to fix it, or even should I be really bothered with this notice from query analyzer.

Second question is regarding performace, since for this query, it using temporary and filesort, I was thinking of creating a view out of this query, and use it instead of actually executing the query each time some product is opened.

Mind you that I am not asking for CI model/view/controller tips, just tips on how to optimize this query, and/or suggestions regarding performance and going for views approach...

Any help is much than appreciated.

Answer
SELECT  p.num, prd.*
    FROM  
    (
        SELECT  a.product_id, COUNT(*) AS num
            FROM  orders AS o
            INNER JOIN  order_items AS b  ON o.id = b.order_id
            INNER JOIN  order_items AS a  ON o.id = a.order_id
            WHERE  b.product_id = '14211'
              AND  a.product_id <> '14211'
            GROUP BY  a.product_id
            ORDER BY  num DESC
            LIMIT  3 
    ) AS p
    JOIN  products AS prd  ON p.product_id = prd.id
    ORDER BY  p.num DESC

This should

  • Run faster (especially as your data grows),
  • Avoid the group by complaint,
  • not over-inflate the count,
  • etc

Ignore the complaint about GROUP BY and ORDER BY coming from different tables -- that is a performance issue; you need it.

As for translating that back to CodeIgniter, good luck.