2011-07-18 33 views
0

我有一個查詢來選擇訂單,並且我需要獲取每個訂單的產品清單,其中包含每個產品的彙總數量。慢速查詢SELECT ...兩個表字段上的SELECT ... GROUP BY(MySQL/InnoDB)

目前,它的速度很慢(10秒我的設置),我需要加快速度。

更新:切換到的MyISAM是不是一種選擇,我需要交易

查詢目前是這樣的:

SELECT `Order`.*, `Product`.`id`, `Product`.`msrp`, SUM(`OrderItem`.`quantity`) AS sum 
FROM `orders` AS `Order` 
LEFT JOIN `order_items` AS `OrderItem` ON (`OrderItem`.`order_id` = `Order`.`id`) 
LEFT JOIN `product_variations` AS `ProductVariation` ON (`OrderItem`.`product_variation_id` = `ProductVariation`.`id`) 
LEFT JOIN `products` AS `Product` ON (`ProductVariation`.`product_id` = `Product`.`id`) 
WHERE 1 = 1 
GROUP BY `Order`.`id`, `Product`.`id` 
ORDER BY `Order`.`created` DESC 
LIMIT 20; 

解釋:

​​

模式(截斷,僅剩下必填字段):

CREATE TABLE `orders` (
    `id` int(11) NOT NULL auto_increment, 
    `created` timestamp NOT NULL default CURRENT_TIMESTAMP, 
    `customer_comments` text NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `created` (`created`), 
    KEY `id_created` (`id`,`created`), 
) ENGINE=InnoDB 

CREATE TABLE `order_items` (
    `id` int(11) NOT NULL auto_increment, 
    `order_id` int(11) NOT NULL, 
    `product_variation_id` int(11) NOT NULL, 
    `type` enum('First','Second') default NULL, 
    `quantity` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `item_UNIQUE` (`order_id`,`product_variation_id`,`type`), 
    KEY `fk_order_items_product_variations1` (`product_variation_id`), 
    CONSTRAINT `fk_order_items_orders1` FOREIGN KEY (`order_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, 
    CONSTRAINT `fk_order_items_product_variations1` FOREIGN KEY (`product_variation_id`) REFERENCES `product_variations` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION 
) ENGINE=InnoDB 

CREATE TABLE `product_variations` (
    `id` int(11) NOT NULL auto_increment, 
    `product_id` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    CONSTRAINT `fk_product_variations_products1` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, 
) ENGINE=InnoDB 

CREATE TABLE `products` (
    `id` int(11) NOT NULL auto_increment, 
    `msrp` decimal(5,2) NOT NULL, 
    PRIMARY KEY (`id`), 
) ENGINE=InnoDB 

服務器是MySQL 5.0.77,表是InnoDB。 orders大約是75K的記錄,order_items 160K記錄,product_variations 140K記錄,product - 300條記錄。

任何幫助表示讚賞。

回答

1

我想嘗試的第一件事是用一個預先計算product_sum表更換SUM。據瞭解,InnoDB在聚合函數方面速度較慢(尤其是75k +行!)。你真的不想每次查詢都計算這個總和(除非數據經常變化)。

使用在插入/更新命令後重新計算product_sum表的觸發器可能會有所幫助..但它不太清楚此查詢的上下文是什麼(是由最終用戶運行的嗎?它是一個網絡請求或報告?等)。

另一種選擇是切換引擎的MyISAM(這是與骨料快很多),但是巨大的負面有你失去交易和外鍵約束。

+0

作爲最後手段,我舉行了預計算和和其他聚合。我的理解是,如果RDBMS擅長某些事情 - 那就是過濾,分組和集合。我當然可以預先計算所有聚合,爲什麼要使用RDBMS呢? – lxa

+0

關於上下文 - 它是網頁界面分頁查詢; (實際上是其中的一部分 - 我需要爲每個「訂單」再總結一次 - 不確定如何執行此操作,因爲WITH ROLLUP不適用於此查詢)。 – lxa

+0

這裏的問題不在於RDBMS,而在於表引擎。切換到MyISAM只是爲了測試聚合是否確實是瓶頸。 InnoDB在聚合時讀取每一行,而MyISAM則不會。所以不幸的是,如果你想要InnoDB的事務/約束特性,你必須自己緩存聚合。 – Matt

1

儘管您的查詢看起來結構良好並且結合在一起,但記錄量可能是問題所在。您可以通過在的地方羣體等我想補充ONE條款等

SELECT STAIGHT_JOIN ...查詢的其餘部分。

的STRAIGHT_JOIN告訴引擎做的順序,你嘗試優化較小的表作爲主已經說明,而不是它,然後在意圖的一些相反順序加入。我已經看到STRAIGHT_JOIN在幾個其他領域的表現令人驚歎,也許它可以幫助你。

+0

不幸的是,不在這一個。試過了 - 沒有顯着差異。 – lxa