简体   繁体   中英

Optimize mysql query Suppliers <-> Products <-> Categories with DISTINCT

My DB is like this: Products are N:N to Categories so there is a join table (products_categories). Products have a Supplier (1 and only 1), so Products table have a supplier_id. Products are about 500K, categories about 200 and suppliers about 80.

Right now I want to get the Distinct suppliers for Products with status = 1 and in categories 2,3 and 125.

My SQL:

SELECT DISTINCT s.id FROM suppliers s INNER JOIN products AS p ON p.supplier_id = s.id INNER JOIN products_categories AS pc ON p.id = pc.products_id WHERE (p.color IN ('red', 'blue')) AND pc.categories_id IN (2,3,125)

The problem with the query is the distinct. Without it the query returns in about 1 second, with DISTINCT it takes about 3 seconds. I have indexes for all FK's / PK.

Explain plan:

id  select_type table   type    possible_keys           key         key_len ref             rows    Extra
1   SIMPLE      pc      range   products_id,categories  categories  4       NULL            28335   Using where; Using temporary
1   SIMPLE      p       eq_ref  PRIMARY,color           PRIMARY     4       pc.products_id      1   Using where
1   SIMPLE      s       eq_ref  PRIMARY                 PRIMARY     4       p.supplier_id       1   Using where; Using index

Adding the distinct adds that "Using temporary" to the explain query plan.

So, is there any way to optimize this query? How to do this distinct in a better way (schema changes are also welcomed if needed)

Have you tried using an EXISTS ?

Something like

SELECT  s.id 
FROM    suppliers s 
WHERE   EXISTS  (
                    SELECT  1
                    FROM    products AS p INNER JOIN 
                            products_categories AS pc ON p.id = pc.products_id 
                    WHERE   (p.supplier_id = s.id)
                    AND     (p.color IN ('red', 'blue')) 
                    AND     pc.categories_id IN (2,3,125)
                )

Try GROUP BY instead of DISTINCT :

SELECT s.id 
FROM suppliers s 
INNER JOIN products AS p ON p.supplier_id = s.id AND p.color IN ('red', 'blue')
INNER JOIN products_categories AS pc USE INDEX (combined_index_name) ON p.id = pc.products_id AND pc.categories_id IN (2,3,125)
GROUP BY s.id 

EDIT

Create a combine index on products_id & categories_id columns of products_categories table. Then check the performance of query.

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