mysql - 通过查询优化 MySQL COUNT/group : show only categories that have products associated

标签 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 表有相当多的索引,有 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/

相关文章:

mysql - 书架级联删除

mysql - 用于传输数据库更改的工具?

sql - 消除 SQL 中的交叉连接

MySQL 日志查询不使用索引和 UNION 误报或错误?

rdbms-agnostic - 业余爱好者的数据库优化技术

MySQL 从包含 unixtime 行的表中选择,但在查询中使用日期时间

sql - 简单的 mysql 查询(我认为) - 选择多行到 1 个字段

php - Mysql 访问被拒绝

java - 在 H2 数据库中插入时间 - 未找到函数 "PARSEDATETIME"

php - 连接多个表中的数据