0

我有 2 张桌子:

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: Using 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 
4

2 回答 2

0

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

如果您想获得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
于 2013-04-23T17:35:26.477 回答
0

您的查询看起来不错,但是,您将其作为 LEFT-JOIN,但通过使用 WHERE 保持 !=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(productid、depotid、remain、remain2)、

于 2013-05-06T11:14:30.343 回答