在两个表字段`上缓慢查询SELECT ... GROUP BY(MySQL / InnoDB)

时间:2011-07-18 11:53:12

标签: mysql performance select group-by

我有一个查询来选择订单,对于每个订单,我需要获得它包含的产品列表以及每个产品的汇总数量。

目前它非常慢(我的设置为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;

解释:

explain results

架构(截断,仅剩下必填字段):

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大约有75,000条记录,order_items 160条记录,product_variations 140条记录,product - 300条记录。

感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

我要尝试的第一件事是用预先计算的product_sum表替换SUM。众所周知,InnoDB的聚合函数较慢(尤其是75k +行!)。你真的不想在每个查询中计算这个总和(除非数据经常变化)。

使用在插入/更新订单后重新计算product_sum表的触发器可能会有所帮助..但是这个查询的上下文不是很清楚(它是由最终用户运行的吗?它是一个web)请求或报告?等等。

另一个选择是将引擎切换到MyISAM(聚合速度要快得多),但是你会失去交易和外键限制,这是一个巨大的负面因素。

答案 1 :(得分:1)

虽然您的查询结构良好且连接在一起,但记录量可能是个问题。你有一个小组,等等。我会添加一个条款...

SELECT STAIGHT_JOIN ...查询的其余部分。

STRAIGHT_JOIN告诉引擎按照你说的顺序执行它,而不是尝试优化较小的表作为主要表,然后加入一些相反的意图顺序。我已经看到STRAIGHT_JOIN在SEVERAL其他领域的表现令人惊叹......也许它可以帮助你。