Mysql GROUP和SUM优化

时间:2013-04-23 17:04:59

标签: mysql performance group-by sum query-optimization

我有两张桌子:

CREATE TABLE IF NOT EXISTS `products` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `categoryId` int(10) unsigned DEFAULT NULL,
  `parentId` int(10) unsigned DEFAULT NULL,
  `barcode` varchar(255) DEFAULT NULL,
  `code` varchar(255) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_products_product_categories1_idx` (`categoryId`),
  KEY `fk_products_products1_idx` (`parentId`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=71521 ;

CREATE TABLE IF NOT EXISTS `inventory` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `depotId` int(10) unsigned NOT NULL,
  `productId` int(10) unsigned NOT NULL,
  `remain` int(11) DEFAULT NULL,
  `remain2` int(10) unsigned DEFAULT NULL,
  `updatedDateTime` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_inventory_depots1_idx` (`depotId`),
  KEY `fk_inventory_products1_idx` (`productId`),
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=89291 ;

请帮我优化以下查询(应该添加什么索引来提高性能),查询耗时0.2578秒(MySQL使用索引fk_inventory_depots1_idx),当删除AND i.depotId = 3时查询耗时0.5484秒。 EXPLAIN查询显示Extra:使用where;使用临时;使用filesort

SELECT `p`.* , SUM(i.remain) AS `remain` , SUM(i.remain2) AS `remain2`
FROM `products` AS `p`
LEFT JOIN `inventory` AS `i` ON p.id = i.productId
WHERE remain != 0 AND i.depotId = 3
GROUP BY `p`.`id`
ORDER BY `p`.`id` DESC
LIMIT 50 

2 个答案:

答案 0 :(得分:0)

语句中使用的sum()函数会考虑所有行(LIMIT子句在最后一次计算时无效)。可能导致全表扫描,因为remainremain2的所有值都已汇总

如果您希望获得最新sum()使用的50 rows

SELECT 
  `p`.* , 
  SUM(i.remain) AS `remain`, 
  SUM(i.remain2) AS `remain2`
FROM
  (
    SELECT `p`.*, 
          i.remain, 
          i.remain2 
    FROM 
      `products` AS `p`
      JOIN `inventory` AS `i` ON p.id = i.productId << This should be a JOIN, as remain and depotId belong to inventory
    WHERE 
      remain != 0 
      AND i.depotId = 3
    GROUP BY 
      `p`.`id`
    ORDER BY 
      `p`.`id` DESC
LIMIT 50  ) as t

答案 1 :(得分:0)

您的查询看起来没问题,但是,您将其作为LEFT-JOIN,但通过使用WHERE,保留!= 0和i.DepotID = 3强制它进入INNER-JOIN。如果你真的打算只有HAD非零剩余数量的条目,那么你没问题。但是,如果您想要库存产品,则必须将查询调整为

SELECT 
      `p`.* , 
      SUM(i.remain) AS `remain` , 
      SUM(i.remain2) AS `remain2`
   FROM `
      products` AS `p`
         LEFT JOIN `inventory` AS `i` 
            ON p.id = i.productId
           AND remain != 0 
           AND i.depotId = 3
   GROUP BY 
      `p`.`id`
   ORDER BY 
      `p`.`id` DESC
   LIMIT 50 

注意&#34; ON&#34;的细微差别。加入条件。这允许所有产品 - 无论匹配的库存记录如何。现在,那就是说,你现在从所有库存中获取,而不仅仅是你的&#34; DepotID = 3&#34;标准。

为了帮助您建立索引,我唯一建议的是多字段密钥。在这种情况下,您使用表中的大多数字段来表示JOIN或SUM()。如果字段是索引的一部分,则不必返回每条记录的实际数据页。小浪费,但可能会改善你的最终结果。

KEY fk_inventory_multiplefields_idx(productid,depotid,remaining,remaining2),