请建议我如何在MySQL中加快此查询的性能。它运行得很慢。
查询:
SELECT *
FROM product, search_attribute, search_attribute_values
WHERE
product.categoryid = 4800 AND product.productid = search_attribute.productid
AND search_attribute.valueid = search_attribute_values.valueid
GROUP BY search_attribute.valueid
查询的解析:
+----+-------------+-------------------------+--------+-----------------------------+---------+---------+-------------------------------------+----------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------------------+--------+-----------------------------+---------+---------+-------------------------------------+----------+---------------------------------+
| 1 | SIMPLE | search_attribute | ALL | PRIMARY,attributeid_valueid | NULL | NULL | NULL | 79801024 | Using temporary; Using filesort |
| 1 | SIMPLE | search_attribute_values | eq_ref | PRIMARY | PRIMARY | 4 | microcad.search_attribute.valueid | 1 | |
| 1 | SIMPLE | product | eq_ref | PRIMARY,product_categoryID | PRIMARY | 4 | microcad.search_attribute.productid | 1 | Using where |
+----+-------------+-------------------------+--------+-----------------------------+---------+---------+-------------------------------------+----------+---------------------------------+
架构:
--
-- Table structure for table `attributenames`
--
DROP TABLE IF EXISTS `attributenames`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `attributenames` (
`attributeid` bigint(20) NOT NULL DEFAULT '0',
`name` varchar(110) NOT NULL DEFAULT '',
`localeid` int(11) NOT NULL DEFAULT '0',
KEY `attributenames_attributeID` (`attributeid`),
KEY `attributenames_localeID` (`localeid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `product`
--
DROP TABLE IF EXISTS `product`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `product` (
`productid` int(11) NOT NULL DEFAULT '0',
`manufacturerid` int(11) NOT NULL DEFAULT '0',
`isactive` tinyint(1) NOT NULL DEFAULT '1',
`mfgpartno` varchar(70) NOT NULL DEFAULT '',
`categoryid` int(11) NOT NULL DEFAULT '0',
`isaccessory` tinyint(1) NOT NULL DEFAULT '0',
`equivalency` double NOT NULL DEFAULT '0',
`creationdate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`modifieddate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`lastupdated` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`productid`),
KEY `product_manufacturerID` (`manufacturerid`),
KEY `product_categoryID` (`categoryid`),
KEY `product_mfgPartNo` (`mfgpartno`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `search_attribute`
--
DROP TABLE IF EXISTS `search_attribute`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `search_attribute` (
`productid` int(11) NOT NULL DEFAULT '0',
`attributeid` bigint(20) NOT NULL DEFAULT '0',
`valueid` int(11) NOT NULL DEFAULT '0',
`localeid` int(11) NOT NULL DEFAULT '0',
`setnumber` tinyint(2) NOT NULL DEFAULT '0',
`isactive` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`productid`,`localeid`,`attributeid`,`setnumber`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `search_attribute_values`
--
DROP TABLE IF EXISTS `search_attribute_values`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `search_attribute_values` (
`valueid` int(11) NOT NULL DEFAULT '0',
`value` varchar(255) NOT NULL DEFAULT '',
`absolutevalue` double NOT NULL DEFAULT '0',
`unitid` int(11) NOT NULL DEFAULT '0',
`isabsolute` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`valueid`),
KEY `search_attrval_value` (`value`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
每个表中的记录数:
search_attribute是72,000,000, search_attribute_values是350,000, 产品是4,000,000
答案 0 :(得分:0)
你可以通过在所有用于从表中获取数据的列添加索引来提高查询性能,例如,在where子句中提到的列。
所以你创建了复合主键,但是你使用search_attribute.valueid查询,因此必须添加另一个索引。
ALTER TABLE `search_attribute` ADD INDEX `valueid ` (`valueid `)
ALTER TABLE `search_attribute` ADD INDEX `productid ` (`productid `)
这很可能会提高性能。
答案 1 :(得分:0)
你的索引应该都很好。 product表有一个categoryid索引,然后它应该从那个连接到search_attribute,它在多个列上有一个覆盖索引,第一个是productid(应该使用)。然后它应该使用valueid作为主键加入search_attribute_values。
然而由于某种原因,MySQL似乎决定对search_attribute进行非键控读取,返回大量行,然后尝试将其他行加入其中。可能是因为GROUP BY(可能会为返回的所有其他列返回奇怪的值)。
我要尝试的第一件事就是强制MySQL重建索引统计信息(使用ANALYZE TABLE)。然后它可能会有用地使用它们。
没有尝试使用STRAIGHT_JOIN: -
SELECT *
FROM product
STRAIGHT_JOIN search_attribute ON product.productid = search_attribute.productid
STRAIGHT_JOIN search_attribute_values ON search_attribute.valueid = search_attribute_values.valueid
WHERE product.categoryid = 4800
GROUP BY search_attribute.valueid
但是,您实际想要返回什么值?例如,对于每个search_attribute valueid,您的查询将返回1个类别ID为4800的产品。返回的是哪个产品未定义,并且类似地假设多个搜索属性可以具有相同的valueid,那么也不会定义哪一个。
虽然这并没有出现错误并且确实在MySQL中返回了某些内容,但它会在大多数SQL中出错。
答案 2 :(得分:0)
请使用JOIN...ON
语法:
SELECT *
FROM product AS p
JOIN search_attribute AS sa ON p.productid = sa.productid
JOIN search_attribute_values AS sav ON sa.valueid = sav.valueid
WHERE p.categoryid = 4800
GROUP BY sa.valueid
您的GROUP BY
无效,因为*
中有许多字段(GROUP BY
)既未包含在COUNT
中也不是聚合(SUM
,{{1}等等)。
InnoDB会更好。
这会欺骗它使用categoryid上的索引,而不是从72M行表开始:
SELECT *
FROM
( SELECT *
FROM product AS p
JOIN search_attribute AS sa ON p.productid = sa.productid
JOIN search_attribute_values AS sav ON sa.valueid = sav.valueid
WHERE p.categoryid = 4800
) x
GROUP BY x.valueid
但它仍存在*
的问题。