简体   繁体   中英

Slow Mysql Query with 3 left join

We have a e-store and in this e-store there is many complicated links between categories and products.

I'm using Taxonomy table in order to store relations between Products-Categories and Products-Products as sub product.

Products may be member of more than one category. Products may be a sub product a sub product of an other product. (May be more than one) Products may be a module of an other product (May be more than one)

aliases of query : pr-Product ct-Category sp-Sub Product md-Module

Select pr.*,ifnull(sp.destination_id,0) as `top_id`,
    ifnull(ct.destination_id,0) as `category_id` 
from Products as pr
Left join Taxonomy as ct
  on (ct.source_id=pr.id and ct.source='Products' and ct.destination='Categories')
Left join Taxonomy as sp 
  on (sp.source_id=pr.id and sp.source='Products' and sp.destination='Products' and sp.type='TOPID')
Left join Modules as md
  on(pr.id = md.product_id)
where pr.deleted=false
  and ct.destination_id='47'
  and sp.destination_id is null
  and md.product_id is null
order by pr.order,pr.sub_order

With this query; I'm trying to get all products under Category_id=47 and not module of any product and not sub product of any product.

This query takes 23 seconds. There is 7.820 Records in Products, 3.200 Records in Modules and 19.000 records in Taxonomy

I was going to say that MySQL can only use one index per query but it looks like that is no longer the case. I also came across this in another answer: http://dev.mysql.com/doc/mysql/en/index-merge-optimization.html

However that may not help you.

In the past, when I've come across queries MySQL couldn't optimised I've settled for precomputing answers in another table using a background job.

What you're trying to do looks like a good fit for a graph database like neo4j.

MySQL's optimizer is known to be bad in changing Outer to Inner joins automatically, it does the outer join first and then starts to filter data.

In your case the join between Products and Taxonomy can be rewritten as an Inner Join (there's a WHERE-condition on ct.destination_id='47').

Try if this changes the execution plan and improves performance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM