【问题标题】:Mysql GROUP BY optimization with inner joins and large datasetMysql GROUP BY 优化与内部连接和大型数据集
【发布时间】:2016-08-05 16:41:24
【问题描述】:

您好,我有一个产品类别数据库,其中产品和类别使用第三个表具有多对多关系,例如。产品分类。现在,我在数据库上运行一个查询,以获取属于类别 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

products 表有大约 23k 行,product_category 表有 26k 行。

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

现在这个查询需要 300 毫秒 来获取结果。如果我删除 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

查询说明如下:

所以,我的问题是,是否有办法专门优化查询组,以便加载结果不会花费太长时间。

【问题讨论】:

  • 既然你没有聚合,你试过SELECT DISTINCT p.*吗?
  • @Uueerdo 是的,我有,没有任何变化,使用 Select Distinct 的查询与使用 group by 的时间差不多。谢谢
  • 你永远不应该使用 group by 结构,因为它不能保证在你没有在 group by 中指定的字段中总是给出相同的结果。仅仅因为您可以做某事并不意味着您应该这样做。按照所有其他数据库所需的方式正确使用 group by。当你有一个连接时,也永远不要使用 SELECT *,因为它返回的数据比你需要的多(连接字段是重复的),这会导致查询速度变慢。这两个语法问题都是 SQL 反模式,如果你试图让真正了解数据库的人通过代码审查,你会不及格。
  • @HLGEM 感谢您提供的建议,选择中的 * 用于简洁。作为数据库专家,您能回答我的问题吗?

标签: mysql database


【解决方案1】:

正如我在评论中所说,您可能对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

编辑:如果这些都没有帮助,您可能希望研究索引WHERE 和ON 条件中使用的字段。

【讨论】:

    猜你喜欢
    • 2013-01-08
    • 2012-12-09
    • 2012-06-12
    • 2011-09-19
    • 2012-10-20
    • 1970-01-01
    • 2013-01-03
    • 1970-01-01
    相关资源
    最近更新 更多