按查询优化MySQL COUNT / group:仅显示包含相关产品的类别

时间:2016-02-22 02:54:24

标签: mysql sql sql-optimization

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_categories和categories表。产品表有大约400k产品,150个类别和500k产品_categories。

在AWS RDS上托管的MySQL 5.6.22,InnoDB中的所有表。

我理解我的解释查询显示为什么这很慢(通过很多产品),但我没有任何想法如何优化这个...可能有不同的方式来考虑这个?

2 个答案:

答案 0 :(得分:0)

对于此查询:

#table-of-grades

您需要所有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; 键的索引。我建议joinproducts(status, gender, id)products_categories(products_id, categories_id)

有时,在MySQL中,使用相关子查询比使用categories(id)更快:

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)上的索引。

答案 1 :(得分:0)

您的查询返回139107个匹配记录,因为您使用的过滤条件不是很有限(状态= 1,性别=女性或中性)。试试这个

this.request.post(
    requestData,
    function (successResponse) {
        // Do whatever with response
    },
    function (failResponse) {
        // Do whatever with response
    }
);

添加url不会自动改善查询。问题是您的过滤条件会返回许多匹配的产品。按性别或布尔状态(true / false)过滤记录可能会因为许多重复值而导致表扫描,即使状态和性别是索引,MySQL仍然认为运行表扫描比使用索引更便宜。

requestData用于过滤没有产品的任何类别。试试这个

SELECT cat.id, cat.name, cat.parent_id AS `parent_id`,
      COUNT(p.id) AS `num` 
FROM `categories` AS `cat`
INNER JOIN `products_categories` AS `pc` ON pc.categories_id=cat.id 
INNER JOIN products AS p ON p.id=pc.products_id 
WHERE p.status = 1 AND p.gender IN ('female','neutral') 
GROUP BY cat.id
HAVING COUNT(p.id)>0

以上查询不会与产品表一起加入。如果他们有产品关联,只需查看product_categories。