使用内部联接和大型数据集进行Mysql GROUP BY优化

时间:2016-08-05 16:41:24

标签: mysql database

您好我有一个产品类别数据库,其中产品和类别使用第三个表格具有多对多的关系,例如。产品分类。现在,我在数据库上运行查询以获取属于类别ID数组上给出的类别的所有产品,让我们看一下以下示例:

SELECT * FROM products p JOIN product_category pc ON p.id = pc.product_id
WHERE pc.category_id IN (1,2,3,4,5,6) GROUP BY p.id LIMIT 0,40

产品表有大约23k行,product_category表有26k行。

通常,WHERE IN子句中使用的类别ID数组包含更多元素。

现在此查询需要 300ms 才能获取结果。如果我删除GROUP BY子句,那么查询只需 2ms 来获取结果。

更完整的查询如下:

select * from `products` inner join `product_category` on `products`.`id` = `product_category`.`product_id`
        where `product_category`.`category_id` in ('1', '2', '3', '4', '5', '6', '7', 
    '8', '44', '155', '156', '157', '158', '159', '160', '161', '162', '168', '169', '171', '172', '173', '174', '175', '176', 
    '178', '179', '180', '181', '182', '183', '184', '185', '186', '189', '190', '191', '192', '193', '194', '195', '196',
     '197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '213', '215', '216', '217', 
    '218', '219', '230', '231', '232', '233', 
    '234', '235', '236', '237', '240', '241', 
    '242', '243', '244', '245', '246', '247', 
    '248', '249', '250', '251', '252', '253', 
    '254', '255', '256', '257', '258', '259', 
    '260', '261', '325', '326', '327', '328', 
    '334', '335', '336', '337', '338', '339', '340', '341', '342', '343', '344') and `products`.`is_visible` = '1' 
    group by `product_category`.`product_id` 
    order by `popularity` desc, `popularity` desc limit 40 offset 0

查询说明如下:

Explain of the query

所以,我的问题是,是否有一种方法可以专门针对该组优化查询,因此不需要太长时间来加载结果。

1 个答案:

答案 0 :(得分:0)

正如我在评论中所说,你可能会对SELECT DISTINCT p.*感到幸运;但我经常看到有人使用GROUP BY来缓解DISTINCT缓慢......

另一种选择是使用子查询而不是直接JOIN,如下所示:

SELECT * 
FROM `products` 
WHERE id IN (
   SELECT DISTINCT `product_id` 
   FROM `product_category` 
   WHERE `category_id` IN ([category id list])
) 
AND `is_visible` = '1' 
ORDER BY `popularity` DESC, `popularity` DESC
LIMIT 40 OFFSET 0

SELECT p.* 
FROM `products` AS p
INNER JOIN (
   SELECT DISTINCT `product_id` 
   FROM `product_category` 
   WHERE `category_id` IN ([category id list])
) AS pcSmry ON p.id = pcSmry.product_id
WHERE p.`is_visible` = '1' 
ORDER BY `popularity` DESC, `popularity` DESC
LIMIT 40 OFFSET 0

编辑:如果这些都没有帮助,您可能希望查看索引WHEREON条件中使用的字段。