select COUNT(p.id) AS `num`, cat.id, cat.name, cat.parent_id AS `parent_id`
from products p
INNER JOIN `products_categories` AS `pc` ON p.id=pc.products_id
INNER JOIN `categories` AS `cat` ON pc.categories_id=cat.id
WHERE p.status = 1 AND p.gender IN ('female','neutral')
group by cat.id
解释查询:
1 SIMPLE p ref PRIMARY,gender,status status 1 const 139107 Using where; Using temporary; Using filesort
1 SIMPLE pc ref products_id,categories products_id 4 mydb.p.id 1 Using index
1 SIMPLE cat eq_ref PRIMARY,categoryname PRIMARY 4 mydb.pc.categories_id 1 Using where
相关索引:
products 0 PRIMARY 1 id A 299339 BTREE
products 1 title 1 title A 299339 BTREE
products 1 sku 1 sku A 299339 BTREE
products 1 body 1 body A 299339 200 BTREE
products 1 short_description 1 short_description A 299339 200 YES BTREE
products 1 keywords 1 keywords A 2 200 BTREE
products 1 gender 1 gender A 10 BTREE
products 1 status 1 status A 2 BTREE
products 1 brand_id 1 brand_id A 3741 YES BTREE
products 1 merchant 1 merchant_id A 52 BTREE
products 1 title_2 1 title,body,keywords 299339 FULLTEXT
products 1 title_3 1 title 299339 FULLTEXT
products 1 body_2 1 body 299339 FULLTEXT
products_categories 0 PRIMARY 1 id A 514054 BTREE
products_categories 1 products_id 1 products_id, categories_id A 514054 BTREE
products_categories 1 categories 1 categories_id A 266 BTREE
categories 0 PRIMARY 1 id A 154 BTREE
categories 1 categoryname 1 name A 154 BTREE
这是一个包含产品、类别以及它们之间的 N:N 关系的数据库。产品可以属于 1 个或多个类别。
我基本上需要一个查询来告诉我,对于当前的产品过滤器(在本例中为状态和性别),该类别是否有任何产品(这样我可以隐藏没有产品的类别)。目前我通过统计每个类别内的产品来了解这一点。
查询 WHERE 参数将根据用户选择的过滤器进行更改,因此该部分在此优化中并不是非常重要。
我不需要某个类别的产品的确切数量,只要他们是否有产品即可。 Products 表有相当多的索引,有 products_categories 和categories 表。 Products 表包含约 400k 个产品、150 个类别和 500k 个 products_categories。
MySQL 5.6.22 托管在 AWS RDS 上,所有表都在 InnoDB 中。
我理解我的解释查询显示了为什么这很慢(经过很多产品),但我不知道如何优化它......也许有不同的思考方式?
最佳答案
对于此查询:
select COUNT(p.id) AS `num`, cat.id, cat.name, cat.parent_id AS `parent_id`
from products p INNER JOIN
products_categories `pc`
ON p.id = pc.products_id INNER JOIN
categories cat
ON pc.categories_id = cat.id
WHERE p.status = 1 AND p.gender IN ('female', 'neutral')
group by cat.id;
您需要所有join
键上的索引。我会推荐产品(状态、性别、id)
、products_categories(products_id、categories_id)
和categories(id)
。
有时,在 MySQL 中,使用相关子查询比 group by
更快:
select c.*,
(select count(*)
from products_categories `pc` INNER JOIN
products p
ON p.id = pc.products_id
where pc.categories_id = cat.id AND
p.status = 1 AND p.gender IN ('female', 'neutral')
) as cnt
from categories c;
此版本需要对 products_categories(categories_id, products_id)
和 products(id, status, sex)
建立索引。
关于mysql - 通过查询优化 MySQL COUNT/group : show only categories that have products associated,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35545071/