Slow MySQL Query Performance

六月ゝ 毕业季﹏ 提交于 2019-12-25 03:34:30

问题


Please suggest how I can speed up performance of this query in MySQL. It runs very slowly.

Query:

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

EXPLAIN of the query:

+----+-------------+-------------------------+--------+-----------------------------+---------+---------+-------------------------------------+----------+---------------------------------+
| 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                     |
+----+-------------+-------------------------+--------+-----------------------------+---------+---------+-------------------------------------+----------+---------------------------------+

Schema:

--
-- 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 */;

Number of Records in each table:

search_attribute is 72,000,000, search_attribute_values is 350,000, product is 4,000,000


回答1:


Your indexes as they stand should all be fine. The product table has an index on categoryid, and it should then join from that to search_attribute which has a covering index on multiple columns, the first of which is productid (which should be used). Then it should join on to search_attribute_values using the valueid which is the primary key.

However for some reason MySQL seems to have decided to do a non keyed read on search_attribute returning a massive number of rows, and then tried to join the others on to that. Possibly because of the GROUP BY (which is probably going to return strange values for all the other columns returned).

First thing I would try is to force MySQL to rebuild the index statistics ( using ANALYZE TABLE). Then it might use them usefully.

Failing that try using a 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

However, what values do you actually want to return? For example your query will return 1 product with a category id of 4800 for each search_attribute valueid. Which product that is returned is not defined, and similarly assuming several search attributes can have the same valueid then which one of those is chosen is also not defined.

While this doesn't error and does return something in MySQL, it would give an error in most flavours of SQL.




回答2:


YOu can improve the performance of your query by adding index on all columns using which you are fetching data from tables i.e., the columns you have mentioned in where clauses.

So you have created composite primary key but you are querying using search_attribute.valueid ,hence another index must be added.

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

Most probably this will improve the performance.




回答3:


Please use JOIN...ON syntax:

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 

Your GROUP BY is not valid since there are many fields (in *) that are neither included in the GROUP BY nor are aggregates (COUNT, SUM, etc).

InnoDB would be better.

This would trick it into using the index on categoryid and not start with the 72M-row table:

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 

But it still has issues with *.



来源:https://stackoverflow.com/questions/34084531/slow-mysql-query-performance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!