2013-04-23 36 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)