2013-04-23 34 views
0

我有2个表:Mysql的集团和SUM优化

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;使用临时;使用文件排序

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 
+0

上创建'inventory'表'(的productId,保持,depotId)'一个索引。希望这有助于... – Meherzad 2013-04-26 05:36:53

回答

0

在语句中使用的sum()功能,将考虑所有行(作为其在最后计算的LIMIT条款将是无效的)。在可能会造成全表扫描作为remain所有的值,remain2归纳起来

如果你想获得最新的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 
+0

我不能在这里使用JOIN,因为有些产品没有留在库存表 – Kevin 2013-04-24 04:29:24

+0

但是你的'WHERE'子句使用来自发明者的字段chking(我假设i.remain,i.remain2,保留属于发明人表 – Akash 2013-04-24 04:59:03

0

您的查询看起来不错的sum(),但是,你将它作为一个LEFT-JOIN,但是通过使用WHERE remaining!= 0和i.DepotID = 3强制它成为一个INNER-JOIN。如果您确实只打算拥有非零剩余数量的条目,那么您就可以。但是,如果你希望库存产品不管,你必须查询调整

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 

请注意,在“ON”的连接条件的细微差别。这允许所有产品 - 不管匹配的库存记录如何。现在,这就是说,你现在从所有的库存中获得,而不仅仅是你的“DepotID = 3”标准。

为了帮助您的索引,我会建议的仅仅是多场关键。在这种情况下,您正在使用JOIN或SUM()目的表中的大多数字段。如果这些字段是索引的一部分,则不必返回到每个记录的实际数据页面。小浪费,但可能会改善您的最终结果。

KEY fk_inventory_multiplefields_idx(产品ID,depotid,保持,remain2)