2015-12-04 123 views
0

請建議我如何在MySQL中加快此查詢的性能。它運行非常緩慢。緩慢的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      | 
+----+-------------+-------------------------+--------+-----------------------------+---------+---------+-------------------------------------+----------+---------------------------------+ 

模式:

search_attribute是72,000,000,01:

-- 
-- 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_values 350,000, 產品將達400萬

+0

將索引添加到您在where子句中使用的字段。另外考慮使用連接。 – blairmeister

回答

0

您的索引,因爲他們站在一切都應該沒事。產品表在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。沒有定義返回的產品,同樣假定幾個搜索屬性可以具有相同的值,那麼也沒有定義選擇哪一個。

儘管這並不是錯誤,並且在MySQL中返回某些內容,但它會在大多數SQL中產生錯誤。

+0

做ANALYZE TABLE完美地解決了我的疑問!謝謝! – Aaron

+0

我現在有類似的問題,請看這裏:http://stackoverflow.com/questions/34125650/slow-mysql-query-copying-to-tmp-table-using-filesort – Aaron

0

您可以通過添加使用您從表即取數據中的所有列索引提高查詢性能,您在where子句中提到的列。

因此,您已經創建了複合主鍵,但是您正在使用search_attribute.valueid查詢,因此必須添加另一個索引。

ALTER TABLE `search_attribute` ADD INDEX `valueid ` (`valueid `) 
ALTER TABLE `search_attribute` ADD INDEX `productid ` (`productid `) 

很可能這會提高性能。

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也不是聚集(COUNTSUM等)許多字段(*)。

InnoDB會更好。

這將誘騙到使用類別ID上的指數並沒有隨着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 

但它仍然有問題與*