Christian Owens
Christian Owens

Reputation: 1116

ORDER BY Causes MySQL query to become Extremely Slow

I have the following query:

SELECT * 
FROM   products 
   INNER JOIN product_meta 
           ON products.id = product_meta.product_id 
   JOIN sales_rights 
     ON product_meta.product_id = sales_rights.product_id 
WHERE  ( products.categories REGEXP '[[:<:]]5[[:>:]]' ) 
   AND ( active = '1' ) 
   AND ( products.show_browse = 1 ) 
   AND ( product_meta.software_platform_mac IS NOT NULL ) 
   AND ( sales_rights.country_id = '240' 
          OR sales_rights.country_id = '223' ) 
GROUP  BY products.id 
ORDER  BY products.avg_rating DESC
LIMIT  0, 18;

Running the query with the omission of the ORDER BY section and the query runs in ~90ms, with the ORDER BY section and the query takes ~8s.

I've browsed around SO and have found the reason for this could be that the sort is being executed before all the data is returned, and instead we should be running ORDER BY on the result set instead? (See this post: Slow query when using ORDER BY)

But I can't quite figure out the definitive way on how I do this?

Upvotes: 3

Views: 2532

Answers (3)

Christian Owens
Christian Owens

Reputation: 1116

The issue in the instance of this query, was that by using GROUP BY and ORDER BY in a query, MySQL is unable to use the index if the GROUP BY and ORDER BY expressions are different.

Related Reading:

Upvotes: 0

I've browsed around SO and have found the reason for this could be that the sort is being executed before all the data is returned, and instead we should be running ORDER BY on the result set instead?

I find that hard to believe, but if that's indeed the issue, I think you'll need to do something like this. (Note where I put the parens.)

select * from
(
  SELECT products.id, products.avg_rating 
  FROM   products 
  INNER JOIN product_meta 
          ON products.id = product_meta.product_id 
  JOIN sales_rights 
    ON product_meta.product_id = sales_rights.product_id 
  WHERE  ( products.categories REGEXP '[[:<:]]5[[:>:]]' ) 
   AND ( active = '1' ) 
   AND ( products.show_browse = 1 ) 
   AND ( product_meta.software_platform_mac IS NOT NULL ) 
   AND ( sales_rights.country_id = '240' 
          OR sales_rights.country_id = '223' ) 
  GROUP  BY products.id 
) as X
ORDER  BY avg_rating DESC
LIMIT  0, 18;

Also, edit your question and include a link to that advice. I think many of us would benefit from reading it.


Additional, possibly unrelated issues

Every column used in a WHERE clause should probably be indexed somehow. Multi-column indexes might perform better for this particular query.

The column products.categories seems to be storing multiple values that you filter with regular expressions. Storing multiple values in a single column is usually a bad idea.

MySQL's GROUP BY is indeterminate. A standard SQL statement using a GROUP BY might return fewer rows, and it might return them faster.

Upvotes: 1

William M-B
William M-B

Reputation: 321

If you can, you may want to index your ID columns so that the query will run quicker. This is a DBA-level solution, rather than a SQL solution - tuning the database will help overall performance.

Upvotes: 0

Related Questions