使用4个JOINS优化MySQL查询

时间:2017-03-16 12:54:18

标签: mysql sql

我需要尽可能优化MySQL查询,因为当前数据库正在崩溃。我们有5个表:

  • 订单 - 包含约200 000条记录
  • 语言 - 包含2-5
  • 记录order_product - 包含超过200 000条记录
  • 产品 - 包含少于100条记录
  • 时事通讯 - 包含超过50 000条记录

当我们尝试在电子邮件中加入简报表时,事情就开始出错了

以下是每个的创建表:

CREATE TABLE `order` (
 `order_id` int(11) NOT NULL AUTO_INCREMENT,
 `order_id_copy` varchar(32) COLLATE utf8_bin NOT NULL,
 `invoice_no` int(11) NOT NULL DEFAULT '0',
 `invoice_prefix` varchar(26) COLLATE utf8_bin NOT NULL,
 `store_id` int(11) NOT NULL DEFAULT '0',
 `store_name` varchar(64) COLLATE utf8_bin NOT NULL,
 `store_url` varchar(255) COLLATE utf8_bin NOT NULL,
 `customer_id` int(11) NOT NULL DEFAULT '0',
 `customer_group_id` int(11) NOT NULL DEFAULT '0',
 `firstname` varchar(32) COLLATE utf8_bin NOT NULL DEFAULT '',
 `lastname` varchar(32) COLLATE utf8_bin NOT NULL,
 `email` varchar(96) COLLATE utf8_bin NOT NULL,
 `telephone` varchar(32) COLLATE utf8_bin NOT NULL DEFAULT '',
 `fax` varchar(32) COLLATE utf8_bin NOT NULL DEFAULT '',
 `payment_firstname` varchar(32) COLLATE utf8_bin NOT NULL DEFAULT '',
 `payment_lastname` varchar(32) COLLATE utf8_bin NOT NULL DEFAULT '',
 `payment_company` varchar(32) COLLATE utf8_bin NOT NULL,
 `payment_company_id` varchar(32) COLLATE utf8_bin NOT NULL,
 `payment_tax_id` varchar(32) COLLATE utf8_bin NOT NULL,
 `payment_address_1` varchar(128) COLLATE utf8_bin NOT NULL,
 `payment_address_2` varchar(128) COLLATE utf8_bin NOT NULL,
 `payment_city` varchar(128) COLLATE utf8_bin NOT NULL,
 `payment_postcode` varchar(10) COLLATE utf8_bin NOT NULL DEFAULT '',
 `payment_country` varchar(128) COLLATE utf8_bin NOT NULL,
 `payment_country_id` int(11) NOT NULL,
 `payment_zone` varchar(128) COLLATE utf8_bin NOT NULL,
 `payment_zone_id` int(11) NOT NULL,
 `payment_address_format` text COLLATE utf8_bin NOT NULL,
 `payment_method` varchar(128) COLLATE utf8_bin NOT NULL DEFAULT '',
 `payment_code` varchar(128) COLLATE utf8_bin NOT NULL,
 `shipping_firstname` varchar(32) COLLATE utf8_bin NOT NULL,
 `shipping_lastname` varchar(32) COLLATE utf8_bin NOT NULL DEFAULT '',
 `shipping_company` varchar(32) COLLATE utf8_bin NOT NULL,
 `shipping_address_1` varchar(128) COLLATE utf8_bin NOT NULL,
 `shipping_address_2` varchar(128) COLLATE utf8_bin NOT NULL,
 `shipping_city` varchar(128) COLLATE utf8_bin NOT NULL,
 `shipping_postcode` varchar(10) COLLATE utf8_bin NOT NULL DEFAULT '',
 `shipping_country` varchar(128) COLLATE utf8_bin NOT NULL,
 `shipping_country_id` int(11) NOT NULL,
 `shipping_zone` varchar(128) COLLATE utf8_bin NOT NULL,
 `shipping_zone_id` int(11) NOT NULL,
 `shipping_address_format` text COLLATE utf8_bin NOT NULL,
 `shipping_method` varchar(128) COLLATE utf8_bin NOT NULL DEFAULT '',
 `shipping_code` varchar(128) COLLATE utf8_bin NOT NULL,
 `comment` text COLLATE utf8_bin NOT NULL,
 `total` decimal(15,4) NOT NULL DEFAULT '0.0000',
 `order_status_id` int(11) NOT NULL DEFAULT '0',
 `affiliate_id` int(11) NOT NULL,
 `commission` decimal(15,4) NOT NULL,
 `language_id` int(11) NOT NULL,
 `currency_id` int(11) NOT NULL,
 `currency_code` varchar(3) COLLATE utf8_bin NOT NULL,
 `currency_value` decimal(15,8) NOT NULL DEFAULT '1.00000000',
 `ip` varchar(15) COLLATE utf8_bin NOT NULL,
 `forwarded_ip` varchar(15) COLLATE utf8_bin NOT NULL,
 `user_agent` varchar(255) COLLATE utf8_bin NOT NULL,
 `accept_language` varchar(255) COLLATE utf8_bin NOT NULL,
 `date_added` datetime NOT NULL,
 `date_modified` datetime NOT NULL,
 `newsletter` tinyint(1) NOT NULL DEFAULT '0',
 PRIMARY KEY (`order_id`),
 KEY `date_added` (`date_added`),
 KEY `date_modified` (`date_modified`),
 KEY `date_added_2` (`date_added`),
 KEY `store_id` (`store_id`),
 KEY `customer_id` (`customer_id`),
 KEY `customer_group_id` (`customer_group_id`),
 KEY `payment_company_id` (`payment_company_id`),
 KEY `payment_tax_id` (`payment_tax_id`),
 KEY `payment_country_id` (`payment_country_id`),
 KEY `payment_zone_id` (`payment_zone_id`),
 KEY `shipping_country_id` (`shipping_country_id`),
 KEY `shipping_zone_id` (`shipping_zone_id`),
 KEY `order_status_id` (`order_status_id`),
 KEY `affiliate_id` (`affiliate_id`),
 KEY `language_id` (`language_id`),
 KEY `currency_id` (`currency_id`)
) ENGINE=MyISAM AUTO_INCREMENT=421544 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

CREATE TABLE `language` (
 `language_id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(32) NOT NULL,
 `code` varchar(5) NOT NULL,
 `locale` varchar(255) NOT NULL,
 `image` varchar(64) NOT NULL,
 `directory` varchar(32) NOT NULL,
 `filename` varchar(64) NOT NULL,
 `sort_order` int(3) NOT NULL DEFAULT '0',
 `status` tinyint(1) NOT NULL,
 PRIMARY KEY (`language_id`),
 KEY `name` (`name`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

CREATE TABLE `order_product` (
 `order_product_id` int(11) NOT NULL AUTO_INCREMENT,
 `order_id` int(11) NOT NULL,
 `product_id` int(11) NOT NULL,
 `name` varchar(255) COLLATE utf8_bin NOT NULL,
 `model` varchar(24) COLLATE utf8_bin NOT NULL,
 `quantity` int(4) NOT NULL,
 `price` decimal(15,4) NOT NULL DEFAULT '0.0000',
 `total` decimal(15,4) NOT NULL DEFAULT '0.0000',
 `tax` decimal(15,4) NOT NULL DEFAULT '0.0000',
 `discount` decimal(15,4) NOT NULL,
 `discount_tax` decimal(15,4) NOT NULL,
 `reward` int(8) NOT NULL,
 PRIMARY KEY (`order_product_id`),
 KEY `order_id` (`order_id`),
 KEY `product_id` (`product_id`)
) ENGINE=MyISAM AUTO_INCREMENT=1243823 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

CREATE TABLE `product` (
 `product_id` int(11) NOT NULL AUTO_INCREMENT,
 `model` varchar(64) NOT NULL,
 `sku` varchar(64) NOT NULL,
 `upc` varchar(12) NOT NULL,
 `ean` varchar(14) NOT NULL,
 `jan` varchar(13) NOT NULL,
 `isbn` varchar(13) NOT NULL,
 `mpn` varchar(64) NOT NULL,
 `location` varchar(128) NOT NULL,
 `quantity` int(4) NOT NULL DEFAULT '0',
 `stock_status_id` int(11) NOT NULL,
 `image` varchar(255) DEFAULT NULL,
 `manufacturer_id` int(11) NOT NULL,
 `shipping` tinyint(1) NOT NULL DEFAULT '1',
 `price` decimal(15,4) NOT NULL DEFAULT '0.0000',
 `points` int(8) NOT NULL DEFAULT '0',
 `tax_class_id` int(11) NOT NULL,
 `date_available` date NOT NULL,
 `weight` decimal(15,8) NOT NULL DEFAULT '0.00000000',
 `weight_class_id` int(11) NOT NULL DEFAULT '0',
 `length` decimal(15,8) NOT NULL DEFAULT '0.00000000',
 `width` decimal(15,8) NOT NULL DEFAULT '0.00000000',
 `height` decimal(15,8) NOT NULL DEFAULT '0.00000000',
 `length_class_id` int(11) NOT NULL DEFAULT '0',
 `subtract` tinyint(1) NOT NULL DEFAULT '1',
 `minimum` int(11) NOT NULL DEFAULT '1',
 `sort_order` int(11) NOT NULL DEFAULT '0',
 `status` tinyint(1) NOT NULL DEFAULT '0',
 `date_added` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
 `date_modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
 `viewed` int(5) NOT NULL DEFAULT '0',
 PRIMARY KEY (`product_id`),
 KEY `model` (`model`),
 KEY `stock_status_id` (`stock_status_id`),
 KEY `manufacturer_id` (`manufacturer_id`),
 KEY `tax_class_id` (`tax_class_id`),
 KEY `weight_class_id` (`weight_class_id`),
 KEY `length_class_id` (`length_class_id`)
) ENGINE=MyISAM AUTO_INCREMENT=135 DEFAULT CHARSET=utf8

CREATE TABLE `newsletter` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `email` varchar(254) NOT NULL,
 `agreed` tinyint(1) NOT NULL DEFAULT '0',
 PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHARSET=utf8

这是SQL:

SELECT o.order_id,
       o.firstname,
       o.lastname,
       o.email,
       o.telephone,
       LOWER(l.code) AS language_code,
       o.currency_code,
       o.total,
       o.date_added,
       o.order_status_id,
       op.product_id,
       p.sku,
       op.price,
       op.model,
       op.name,
       op.tax,
       nl.agreed
FROM `order` o
JOIN LANGUAGE l ON l.language_id = o.language_id
LEFT JOIN order_product op ON op.order_id = o.order_id
LEFT JOIN product p ON p.product_id = op.product_id
LEFT JOIN newsletter nl ON nl.email = o.email
WHERE o.order_status_id IN(3,
                           5)
  AND o.order_id > '0'
ORDER BY o.order_id ASC
LIMIT 1

无法弄清楚我们如何优化SQL,即使我们只做LIMIT 1。

2 个答案:

答案 0 :(得分:0)

我个人试图避免加入varchars。也就是说,如果您无法改进设计,可以考虑在电子邮件列中添加索引,这至少可以提高搜索性能。

希望有所帮助

答案 1 :(得分:0)

如果查询真的很长 - 我尝试添加索引(order_id,order_status_id)+可能会重写ORDER BY

  

ORDER BY o.order_id,order_status_id

在这种情况下,查询应立即完成'

如果仍然没有运气 - 您可以先尝试选择单个订单,然后将其余表格加入该行。

(啊,因为你正在使用myisam - 确保其他查询不会影响执行时间,例如空闲服务器上的基准测试)